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.
- checksums.yaml +8 -8
- data/README.md +172 -147
- data/examples/em_protocol_example.rb +82 -0
- data/examples/em_session_basic_example.rb +85 -0
- data/examples/em_session_interrupt_example.rb +155 -0
- data/lib/client_for_poslynx/data/requests/abstract_request.rb +6 -0
- data/lib/client_for_poslynx/net.rb +2 -1
- data/lib/client_for_poslynx/net/em_connector.rb +344 -0
- data/lib/client_for_poslynx/net/em_connector/callback_map.rb +50 -0
- data/lib/client_for_poslynx/net/em_connector/connection_handler.rb +14 -0
- data/lib/client_for_poslynx/net/em_connector/connector_state.rb +24 -0
- data/lib/client_for_poslynx/net/em_connector/event_dispatcher.rb +66 -0
- data/lib/client_for_poslynx/net/em_connector/handles_connection.rb +57 -0
- data/lib/client_for_poslynx/net/em_connector/request_call.rb +27 -0
- data/lib/client_for_poslynx/net/em_protocol.rb +1 -1
- data/lib/client_for_poslynx/net/em_session.rb +250 -0
- data/lib/client_for_poslynx/version.rb +1 -1
- data/spec/client_for_poslynx/net/em_connector_spec.rb +624 -0
- data/spec/client_for_poslynx/net/em_session_spec.rb +313 -0
- metadata +19 -8
- data/lib/client_for_poslynx/net/structured_client.rb +0 -104
- data/lib/client_for_poslynx/net/structured_client/em_connection.rb +0 -72
- data/spec/client_for_poslynx/net/structured_client_spec.rb +0 -118
@@ -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.
|
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-
|
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/
|
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/
|
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:
|
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/
|
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
|