acquiring-sdk-ruby 0.1.0

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 (174) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +140 -0
  5. data/Rakefile +34 -0
  6. data/acquiring-sdk-ruby.gemspec +30 -0
  7. data/lib/worldline/acquiring/sdk/api_resource.rb +53 -0
  8. data/lib/worldline/acquiring/sdk/authentication/authenticator.rb +21 -0
  9. data/lib/worldline/acquiring/sdk/authentication/authorization_type.rb +17 -0
  10. data/lib/worldline/acquiring/sdk/authentication/oauth2_authenticator.rb +142 -0
  11. data/lib/worldline/acquiring/sdk/authentication/oauth2_exception.rb +15 -0
  12. data/lib/worldline/acquiring/sdk/authentication.rb +1 -0
  13. data/lib/worldline/acquiring/sdk/call_context.rb +9 -0
  14. data/lib/worldline/acquiring/sdk/client.rb +69 -0
  15. data/lib/worldline/acquiring/sdk/communication/communication_exception.rb +21 -0
  16. data/lib/worldline/acquiring/sdk/communication/connection.rb +50 -0
  17. data/lib/worldline/acquiring/sdk/communication/default_connection.rb +429 -0
  18. data/lib/worldline/acquiring/sdk/communication/metadata_provider.rb +162 -0
  19. data/lib/worldline/acquiring/sdk/communication/multipart_form_data_object.rb +54 -0
  20. data/lib/worldline/acquiring/sdk/communication/multipart_form_data_request.rb +15 -0
  21. data/lib/worldline/acquiring/sdk/communication/not_found_exception.rb +21 -0
  22. data/lib/worldline/acquiring/sdk/communication/param_request.rb +16 -0
  23. data/lib/worldline/acquiring/sdk/communication/pooled_connection.rb +28 -0
  24. data/lib/worldline/acquiring/sdk/communication/request_header.rb +64 -0
  25. data/lib/worldline/acquiring/sdk/communication/request_param.rb +30 -0
  26. data/lib/worldline/acquiring/sdk/communication/response_exception.rb +58 -0
  27. data/lib/worldline/acquiring/sdk/communication/response_header.rb +80 -0
  28. data/lib/worldline/acquiring/sdk/communication.rb +1 -0
  29. data/lib/worldline/acquiring/sdk/communicator.rb +506 -0
  30. data/lib/worldline/acquiring/sdk/communicator_configuration.rb +197 -0
  31. data/lib/worldline/acquiring/sdk/domain/data_object.rb +34 -0
  32. data/lib/worldline/acquiring/sdk/domain/shopping_cart_extension.rb +62 -0
  33. data/lib/worldline/acquiring/sdk/domain/uploadable_file.rb +35 -0
  34. data/lib/worldline/acquiring/sdk/domain.rb +1 -0
  35. data/lib/worldline/acquiring/sdk/factory.rb +183 -0
  36. data/lib/worldline/acquiring/sdk/json/default_marshaller.rb +36 -0
  37. data/lib/worldline/acquiring/sdk/json/marshaller.rb +29 -0
  38. data/lib/worldline/acquiring/sdk/json/marshaller_syntax_exception.rb +11 -0
  39. data/lib/worldline/acquiring/sdk/json.rb +1 -0
  40. data/lib/worldline/acquiring/sdk/logging/communicator_logger.rb +26 -0
  41. data/lib/worldline/acquiring/sdk/logging/log_message_builder.rb +91 -0
  42. data/lib/worldline/acquiring/sdk/logging/logging_capable.rb +19 -0
  43. data/lib/worldline/acquiring/sdk/logging/obfuscation/body_obfuscator.rb +101 -0
  44. data/lib/worldline/acquiring/sdk/logging/obfuscation/header_obfuscator.rb +54 -0
  45. data/lib/worldline/acquiring/sdk/logging/obfuscation/obfuscation_capable.rb +23 -0
  46. data/lib/worldline/acquiring/sdk/logging/obfuscation/obfuscation_rule.rb +49 -0
  47. data/lib/worldline/acquiring/sdk/logging/obfuscation.rb +1 -0
  48. data/lib/worldline/acquiring/sdk/logging/request_log_message_builder.rb +52 -0
  49. data/lib/worldline/acquiring/sdk/logging/response_log_message_builder.rb +43 -0
  50. data/lib/worldline/acquiring/sdk/logging/ruby_communicator_logger.rb +63 -0
  51. data/lib/worldline/acquiring/sdk/logging/stdout_communicator_logger.rb +33 -0
  52. data/lib/worldline/acquiring/sdk/logging.rb +1 -0
  53. data/lib/worldline/acquiring/sdk/proxy_configuration.rb +76 -0
  54. data/lib/worldline/acquiring/sdk/v1/acquirer/acquirer_client.rb +35 -0
  55. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/accountverifications/account_verifications_client.rb +60 -0
  56. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/accountverifications.rb +4 -0
  57. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/dynamiccurrencyconversion/dynamic_currency_conversion_client.rb +60 -0
  58. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/dynamiccurrencyconversion.rb +4 -0
  59. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/merchant_client.rb +66 -0
  60. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/payments/get_payment_status_params.rb +34 -0
  61. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/payments/payments_client.rb +224 -0
  62. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/payments.rb +4 -0
  63. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/refunds/get_refund_params.rb +34 -0
  64. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/refunds/refunds_client.rb +157 -0
  65. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/refunds.rb +4 -0
  66. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/technicalreversals/technical_reversals_client.rb +64 -0
  67. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/technicalreversals.rb +4 -0
  68. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant.rb +4 -0
  69. data/lib/worldline/acquiring/sdk/v1/acquirer.rb +4 -0
  70. data/lib/worldline/acquiring/sdk/v1/api_exception.rb +63 -0
  71. data/lib/worldline/acquiring/sdk/v1/authorization_exception.rb +23 -0
  72. data/lib/worldline/acquiring/sdk/v1/domain/address_verification_data.rb +41 -0
  73. data/lib/worldline/acquiring/sdk/v1/domain/amount_data.rb +48 -0
  74. data/lib/worldline/acquiring/sdk/v1/domain/api_account_verification_request.rb +70 -0
  75. data/lib/worldline/acquiring/sdk/v1/domain/api_account_verification_response.rb +87 -0
  76. data/lib/worldline/acquiring/sdk/v1/domain/api_action_response.rb +71 -0
  77. data/lib/worldline/acquiring/sdk/v1/domain/api_action_response_for_refund.rb +71 -0
  78. data/lib/worldline/acquiring/sdk/v1/domain/api_capture_request.rb +75 -0
  79. data/lib/worldline/acquiring/sdk/v1/domain/api_capture_request_for_refund.rb +43 -0
  80. data/lib/worldline/acquiring/sdk/v1/domain/api_increment_request.rb +61 -0
  81. data/lib/worldline/acquiring/sdk/v1/domain/api_increment_response.rb +43 -0
  82. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_error_response.rb +62 -0
  83. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_refund_request.rb +77 -0
  84. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_request.rb +95 -0
  85. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_resource.rb +103 -0
  86. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_response.rb +126 -0
  87. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_reversal_request.rb +61 -0
  88. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_summary_for_response.rb +66 -0
  89. data/lib/worldline/acquiring/sdk/v1/domain/api_references_for_responses.rb +48 -0
  90. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_request.rb +88 -0
  91. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_resource.rb +110 -0
  92. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_response.rb +133 -0
  93. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_summary_for_response.rb +66 -0
  94. data/lib/worldline/acquiring/sdk/v1/domain/api_reversal_response.rb +36 -0
  95. data/lib/worldline/acquiring/sdk/v1/domain/api_technical_reversal_request.rb +50 -0
  96. data/lib/worldline/acquiring/sdk/v1/domain/api_technical_reversal_response.rb +62 -0
  97. data/lib/worldline/acquiring/sdk/v1/domain/card_data_for_dcc.rb +48 -0
  98. data/lib/worldline/acquiring/sdk/v1/domain/card_on_file_data.rb +52 -0
  99. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data.rb +114 -0
  100. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_refund.rb +82 -0
  101. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_resource.rb +43 -0
  102. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_response.rb +52 -0
  103. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_verification.rb +91 -0
  104. data/lib/worldline/acquiring/sdk/v1/domain/dcc_data.rb +55 -0
  105. data/lib/worldline/acquiring/sdk/v1/domain/dcc_proposal.rb +60 -0
  106. data/lib/worldline/acquiring/sdk/v1/domain/e_commerce_data.rb +52 -0
  107. data/lib/worldline/acquiring/sdk/v1/domain/e_commerce_data_for_account_verification.rb +45 -0
  108. data/lib/worldline/acquiring/sdk/v1/domain/e_commerce_data_for_response.rb +41 -0
  109. data/lib/worldline/acquiring/sdk/v1/domain/get_dcc_rate_request.rb +75 -0
  110. data/lib/worldline/acquiring/sdk/v1/domain/get_dcc_rate_response.rb +57 -0
  111. data/lib/worldline/acquiring/sdk/v1/domain/initial_card_on_file_data.rb +41 -0
  112. data/lib/worldline/acquiring/sdk/v1/domain/merchant_data.rb +76 -0
  113. data/lib/worldline/acquiring/sdk/v1/domain/network_token_data.rb +41 -0
  114. data/lib/worldline/acquiring/sdk/v1/domain/payment_references.rb +48 -0
  115. data/lib/worldline/acquiring/sdk/v1/domain/plain_card_data.rb +48 -0
  116. data/lib/worldline/acquiring/sdk/v1/domain/point_of_sale_data.rb +34 -0
  117. data/lib/worldline/acquiring/sdk/v1/domain/point_of_sale_data_for_dcc.rb +41 -0
  118. data/lib/worldline/acquiring/sdk/v1/domain/rate_data.rb +64 -0
  119. data/lib/worldline/acquiring/sdk/v1/domain/sub_operation.rb +94 -0
  120. data/lib/worldline/acquiring/sdk/v1/domain/sub_operation_for_refund.rb +87 -0
  121. data/lib/worldline/acquiring/sdk/v1/domain/subsequent_card_on_file_data.rb +48 -0
  122. data/lib/worldline/acquiring/sdk/v1/domain/three_d_secure.rb +62 -0
  123. data/lib/worldline/acquiring/sdk/v1/domain/transaction_data_for_dcc.rb +52 -0
  124. data/lib/worldline/acquiring/sdk/v1/domain.rb +4 -0
  125. data/lib/worldline/acquiring/sdk/v1/exception_factory.rb +48 -0
  126. data/lib/worldline/acquiring/sdk/v1/ping/ping_client.rb +52 -0
  127. data/lib/worldline/acquiring/sdk/v1/ping.rb +4 -0
  128. data/lib/worldline/acquiring/sdk/v1/platform_exception.rb +23 -0
  129. data/lib/worldline/acquiring/sdk/v1/reference_exception.rb +23 -0
  130. data/lib/worldline/acquiring/sdk/v1/v1_client.rb +43 -0
  131. data/lib/worldline/acquiring/sdk/v1/validation_exception.rb +23 -0
  132. data/lib/worldline/acquiring/sdk/v1.rb +4 -0
  133. data/lib/worldline/acquiring/sdk.rb +1 -0
  134. data/spec/comparable_extension.rb +29 -0
  135. data/spec/fixtures/resources/authentication/oauth2AccessToken.expired.json +4 -0
  136. data/spec/fixtures/resources/authentication/oauth2AccessToken.invalidClient.json +4 -0
  137. data/spec/fixtures/resources/authentication/oauth2AccessToken.json +4 -0
  138. data/spec/fixtures/resources/communication/getWithQueryParams.json +3 -0
  139. data/spec/fixtures/resources/communication/getWithoutQueryParams.json +3 -0
  140. data/spec/fixtures/resources/communication/notFound.html +1 -0
  141. data/spec/fixtures/resources/communication/postWithBadRequestResponse.json +11 -0
  142. data/spec/fixtures/resources/communication/postWithCreatedResponse.json +6 -0
  143. data/spec/fixtures/resources/communication/unknownServerError.json +10 -0
  144. data/spec/fixtures/resources/logging/bodyNoObfuscation.json +7 -0
  145. data/spec/fixtures/resources/logging/bodyWithBinObfuscated.json +3 -0
  146. data/spec/fixtures/resources/logging/bodyWithBinOriginal.json +3 -0
  147. data/spec/fixtures/resources/logging/bodyWithCardCustomObfuscated.json +13 -0
  148. data/spec/fixtures/resources/logging/bodyWithCardObfuscated.json +13 -0
  149. data/spec/fixtures/resources/logging/bodyWithCardOriginal.json +13 -0
  150. data/spec/fixtures/resources/logging/bodyWithObjectObfuscated.json +5 -0
  151. data/spec/fixtures/resources/logging/bodyWithObjectOriginal.json +5 -0
  152. data/spec/fixtures/resources/properties.oauth2.yml +8 -0
  153. data/spec/fixtures/resources/properties.proxy.yml +14 -0
  154. data/spec/integration/connection_pooling_spec.rb +74 -0
  155. data/spec/integration/multipart_form_data_spec.rb +216 -0
  156. data/spec/integration/process_payment_spec.rb +43 -0
  157. data/spec/integration/request_dcc_rate_spec.rb +24 -0
  158. data/spec/integration/sdk_proxy_spec.rb +70 -0
  159. data/spec/integration_setup.rb +111 -0
  160. data/spec/lib/authentication/oauth2_authenticator_spec.rb +68 -0
  161. data/spec/lib/client_spec.rb +47 -0
  162. data/spec/lib/communication/default_connection_logger_spec.rb +484 -0
  163. data/spec/lib/communication/default_connection_spec.rb +352 -0
  164. data/spec/lib/communication/metadata_provider_spec.rb +93 -0
  165. data/spec/lib/communicator_configuration_spec.rb +181 -0
  166. data/spec/lib/communicator_spec.rb +34 -0
  167. data/spec/lib/factory_spec.rb +38 -0
  168. data/spec/lib/json/default_marshaller_spec.rb +39 -0
  169. data/spec/lib/logging/obfuscation/body_obfuscator_spec.rb +86 -0
  170. data/spec/lib/logging/obfuscation/header_obfuscator_spec.rb +100 -0
  171. data/spec/lib/logging/ruby_communicator_logger_spec.rb +92 -0
  172. data/spec/lib/logging/stdout_communicator_logger_spec.rb +64 -0
  173. data/spec/spec_helper.rb +32 -0
  174. metadata +375 -0
@@ -0,0 +1,352 @@
1
+ require 'spec_helper'
2
+ require 'uri'
3
+ require 'stringio'
4
+ require 'sinatra'
5
+
6
+ DefaultConnection ||= Worldline::Acquiring::SDK::Communication::DefaultConnection
7
+ ResponseHeader ||= Worldline::Acquiring::SDK::Communication::ResponseHeader
8
+ StdoutCommunicatorLogger ||= Worldline::Acquiring::SDK::Logging::StdoutCommunicatorLogger
9
+
10
+ describe DefaultConnection do
11
+ let(:connect_timeout) { 10 }
12
+ let(:socket_timeout) { 10 }
13
+ let(:max_connections) { 10 }
14
+ let(:proxy_configuration) { nil }
15
+ subject(:connection) do
16
+ described_class.new(connect_timeout: connect_timeout,
17
+ socket_timeout: socket_timeout,
18
+ max_connections: max_connections,
19
+ proxy_configuration: proxy_configuration)
20
+ end
21
+
22
+ context 'construction' do
23
+ context 'without proxy' do
24
+ let(:proxy_configuration) { nil }
25
+ let(:max_connections) { nil }
26
+
27
+ it 'has the correct timeout values' do
28
+ expect(
29
+ connection.instance_variable_get(:@connect_timeout)
30
+ ).to eq(connect_timeout)
31
+
32
+ expect(
33
+ connection.instance_variable_get(:@socket_timeout)
34
+ ).to eq(socket_timeout)
35
+
36
+ expect(
37
+ connection.instance_variable_get(:@proxy_configuration)
38
+ ).to be_nil
39
+ end
40
+ end
41
+
42
+ context 'with proxy' do
43
+ let(:uri) { URI('http://test-proxy') }
44
+
45
+ context 'without authentication' do
46
+ let(:proxy_configuration) { Worldline::Acquiring::SDK::ProxyConfiguration.new(address: uri) }
47
+
48
+ it 'has the correct timeout values and proxy settings' do
49
+ expect(
50
+ connection.instance_variable_get(:@connect_timeout)
51
+ ).to eq(connect_timeout)
52
+
53
+ expect(
54
+ connection.instance_variable_get(:@socket_timeout)
55
+ ).to eq(socket_timeout)
56
+
57
+ expect(
58
+ connection.instance_variable_get(:@proxy_configuration).host
59
+ ).to eq('test-proxy')
60
+
61
+ expect(
62
+ connection.instance_variable_get(:@proxy_configuration).port
63
+ ).to eq(80)
64
+
65
+ expect(
66
+ connection.instance_variable_get(:@proxy_configuration).scheme
67
+ ).to eq('http')
68
+ end
69
+ end
70
+
71
+ context 'with authentication' do
72
+ let(:username) { 'test-username' }
73
+ let(:password) { 'test-password' }
74
+ let(:proxy_configuration) do
75
+ Worldline::Acquiring::SDK::ProxyConfiguration.new(address: uri,
76
+ username: username,
77
+ password: password)
78
+ end
79
+
80
+ it 'has the correct timeout values and proxy settings' do
81
+ expect(
82
+ connection.instance_variable_get(:@connect_timeout)
83
+ ).to eq(connect_timeout)
84
+
85
+ expect(
86
+ connection.instance_variable_get(:@socket_timeout)
87
+ ).to eq(socket_timeout)
88
+
89
+ pc = connection.instance_variable_get(:@proxy_configuration)
90
+
91
+ expect(pc.host).to eq('test-proxy')
92
+ expect(pc.port).to eq(80)
93
+ expect(pc.scheme).to eq('http')
94
+ expect(pc.username).to eq(username)
95
+ expect(pc.password).to eq(password)
96
+ end
97
+ end
98
+ end
99
+ end # construction
100
+
101
+ context 'sending and receiving' do
102
+
103
+ class DummyResponse
104
+ def pop
105
+ self
106
+ end
107
+
108
+ def status_code
109
+ 200
110
+ end
111
+
112
+ def content
113
+ StringIO.new(body || '')
114
+ end
115
+
116
+ attr_accessor :headers, :body, :content_type, :uri
117
+ end
118
+
119
+ context 'without proxy' do
120
+ before :example do
121
+ # mock the HTTPClient obj inside DefaultConnection
122
+ # for each type of requests so no real requests will be made
123
+ client = connection.instance_variable_get(:@http_client)
124
+ allow(client).to receive(:get_async) do |uri, hash|
125
+ dummy_response = DummyResponse.new
126
+ dummy_response.headers = hash[:header]
127
+ dummy_response.uri = uri
128
+ dummy_response
129
+ end
130
+
131
+ allow(client).to receive(:delete_async) do |uri, hash|
132
+ dummy_response = DummyResponse.new
133
+ dummy_response.headers = hash[:header]
134
+ dummy_response.uri = uri
135
+ dummy_response
136
+ end
137
+
138
+ allow(client).to receive(:post_async) do |uri, hash|
139
+ dummy_response = DummyResponse.new
140
+ dummy_response.headers = hash[:header]
141
+ dummy_response.uri = uri
142
+ dummy_response.body = hash[:body]
143
+ dummy_response
144
+ end
145
+
146
+ allow(client).to receive(:put_async) do |uri, hash|
147
+ dummy_response = DummyResponse.new
148
+ dummy_response.headers = hash[:header]
149
+ dummy_response.uri = uri
150
+ dummy_response.body = hash[:body]
151
+ dummy_response
152
+ end
153
+
154
+ allow(client).to receive(:request_async) do |_method, uri, hash|
155
+ dummy_response = DummyResponse.new
156
+ dummy_response.headers = hash[:header]
157
+ dummy_response.uri = uri
158
+ dummy_response.body = hash[:body]
159
+ dummy_response
160
+ end
161
+ end
162
+
163
+ let(:headers) { { 'Content-Type' => 'application/json', 'header1' => 'dummy', 'header2' => 'yammy' } }
164
+ let(:sdk_headers) { headers.map {|k, v| ResponseHeader.new(k, v) } }
165
+ let(:uri) { URI('http://foobar.com/services/v1/100812/520000214/dcc-rates?source=EUR&amount=1000&target=USD') }
166
+
167
+ def expected_header_str(headers)
168
+ headers.inject('') { |str, (k, v)| %Q{#{str}#{k}="#{v}", }}.chomp(', ')
169
+ end
170
+
171
+ def sdk_headers_to_s(sdk_headers)
172
+ sdk_headers.inject('') { |s, h| s + h.name + ':' + h.value + ',' }
173
+ end
174
+
175
+ it 'sends the correct get request' do
176
+ response_headers = nil
177
+ connection.get(uri, sdk_headers) { |s, h, c| response_headers = h }
178
+ expect(sdk_headers_to_s(response_headers)).to eq(sdk_headers_to_s(sdk_headers))
179
+ end
180
+
181
+ it 'sends the correct delete request' do
182
+ response_headers = nil
183
+ connection.delete(uri, sdk_headers) { |s, h, c| response_headers = h }
184
+ expect(sdk_headers_to_s(response_headers)).to eq(sdk_headers_to_s(sdk_headers))
185
+ end
186
+
187
+ context 'with body' do
188
+ let(:body) { 'dummy body' }
189
+
190
+ it 'sends the correct post request' do
191
+ response_headers = nil
192
+ response_body = ''
193
+ connection.post(uri, sdk_headers, body) { |s, h, c| response_headers, response_body = h, c.read.force_encoding('UTF-8') }
194
+ expect(ResponseHeader.get_header_value(response_headers, 'Content-Type')).to eq('application/json')
195
+ expect(response_body).to eq(body)
196
+ end
197
+
198
+ it 'sends the correct put request' do
199
+ response_headers = nil
200
+ response_body = ''
201
+ connection.put(uri, sdk_headers, body) { |s, h, c| response_headers, response_body = h, c.read.force_encoding('UTF-8') }
202
+ expect(ResponseHeader.get_header_value(response_headers, 'Content-Type')).to eq('application/json')
203
+ expect(response_body).to eq(body)
204
+ end
205
+ end
206
+
207
+ context 'with logging' do
208
+ let(:logger) { StdoutCommunicatorLogger.instance }
209
+ let(:request_regex) do
210
+ # captures:
211
+ # 1) uuid
212
+ # 2) method
213
+ # 3) uri
214
+ # 4) headers
215
+ %r{\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2} Outgoing request \(requestId='([-a-zA-Z0-9]+)'\):
216
+ method: '([A-Z]+)'
217
+ uri: '(.+)'
218
+ headers: '(.*)'}
219
+ end
220
+
221
+ let(:request_with_body_regex) do
222
+ # captures:
223
+ # 1) uuid
224
+ # 2) method
225
+ # 3) uri
226
+ # 4) headers
227
+ # 5) content_type
228
+ # 6) body
229
+ %r{\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2} Outgoing request \(requestId='([-a-zA-Z0-9]+)'\):
230
+ method: '([A-Z]+)'
231
+ uri: '(.+)'
232
+ headers: '(.*)'
233
+ content-type: '(.+)'
234
+ body: '(.+)'}
235
+ end
236
+
237
+ let(:response_regex) do
238
+ # captures:
239
+ # 1) status-cde
240
+ # 2) headers
241
+ # 3) content-type
242
+ # 4) body
243
+ %r{\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2} Incoming response \(requestId='([-a-zA-Z0-9]+)'.*\):
244
+ status-code: '(\d+)'
245
+ headers: '(.*)'
246
+ content-type: '(.*)'
247
+ body: '(.*)'}
248
+ end
249
+
250
+ let(:regex) { Regexp.new(request_regex.to_s + "\n" + response_regex.to_s) }
251
+
252
+ let(:with_body_regex) do
253
+ Regexp.new(request_with_body_regex.to_s + "\n" + response_regex.to_s)
254
+ end
255
+
256
+ before :example do
257
+ $stdout = StringIO.new
258
+ connection.enable_logging(logger)
259
+ end
260
+
261
+ after :example do
262
+ connection.disable_logging
263
+ $stdout.close
264
+ $stdout = STDOUT
265
+ end
266
+
267
+ # TODO: DELETE is basically the same, do we need to test it?
268
+ it 'logs the correct get request' do
269
+ connection.get(uri, sdk_headers) { |s, h, c| }
270
+ expect($stdout.string).to match(regex)
271
+ match_info = $stdout.string.match(regex)
272
+ expect(match_info[2]).to eq('GET')
273
+ expect(match_info[3]).to eq(uri.path + '?' + uri.query)
274
+ expect(match_info[4]).to eq(expected_header_str(headers))
275
+ end
276
+
277
+ # TODO: same for PUT
278
+ context 'with body' do
279
+ let(:body) { 'dummy body' }
280
+ it 'logs the correct post request' do
281
+ connection.post(uri, sdk_headers, body) { |s, h, c| }
282
+ expect($stdout.string).to match(with_body_regex)
283
+ match_info = $stdout.string.match(with_body_regex)
284
+ expect(match_info[2]).to eq('POST')
285
+ expect(match_info[3]).to eq(uri.path + '?' + uri.query)
286
+ headers['Content-Type'] = 'application/json' # with body
287
+ expect(match_info[4]).to eq(expected_header_str(headers))
288
+ expect(match_info[5]).to eq('application/json')
289
+ expect(match_info[6]).to eq(body)
290
+ end
291
+ end
292
+ end
293
+ end
294
+ end # sending and receiving
295
+
296
+ context 'connection' do
297
+ server = nil
298
+ before :context do
299
+ WebMock.allow_net_connect!
300
+ server = Thread.new do
301
+ class DummyServer < Sinatra::Application
302
+ prefix = 'spec/fixtures/resources/communication/'
303
+
304
+ get '/get.json' do
305
+ content_type :json
306
+ IO.read(prefix + 'getWithQueryParams.json')
307
+ end
308
+
309
+ get '/' do
310
+ 'testing'
311
+ end
312
+
313
+ run!
314
+ end
315
+ end
316
+ sleep 1 # wait for the server
317
+ end
318
+
319
+ after :context do
320
+ Thread.kill(server) # shutdown the server
321
+ WebMock.disable_net_connect!
322
+ end
323
+
324
+ before :example do
325
+ connection.close
326
+ end
327
+
328
+ let(:uri) { URI('http://localhost:4567/get.json') }
329
+ let(:sdk_headers) { [] }
330
+
331
+ it 'uses persistent connection if HTTP 1.1 is supported' do
332
+ 100.times { connection.get(uri, sdk_headers) { |x, y| } }
333
+ expect(connection.session_count).to eq(1)
334
+ end
335
+
336
+ it 'retrieves the correct json file' do
337
+ response_body = ''
338
+ connection.get(uri, sdk_headers) { |status, headers, body| response_body = body.read.force_encoding('UTF-8') }
339
+ prefix = 'spec/fixtures/resources/communication/'
340
+ expect(response_body).to eq(IO.read(prefix + 'getWithQueryParams.json'))
341
+ end
342
+
343
+ it 'can explicitly close connections' do
344
+ connection.get(uri, sdk_headers) { |x, y| }
345
+
346
+ connection.close
347
+ expect(connection.session_count).to eq(0)
348
+
349
+ connection.get(uri, sdk_headers) { |x, y| }
350
+ end
351
+ end
352
+ end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+ require 'worldline/acquiring/sdk/domain/shopping_cart_extension'
3
+ require 'base64'
4
+
5
+ describe 'MetadataProvider' do
6
+
7
+ MetadataProvider ||= Worldline::Acquiring::SDK::Communication::MetadataProvider
8
+ RequestHeader ||= Worldline::Acquiring::SDK::Communication::RequestHeader
9
+
10
+ it 'can give metadata_headers with a full shopping cart' do
11
+ shopping_cart_extension = Worldline::Acquiring::SDK::Domain::ShoppingCartExtension.new('Worldline.creator', 'Extension', '1.0', 'ExtensionId')
12
+ metadata_provider = MetadataProvider.new('Worldline', shopping_cart_extension: shopping_cart_extension)
13
+
14
+ request_headers = metadata_provider.metadata_headers
15
+ expect(request_headers.length).to eq(1)
16
+ expect(request_headers.length).to eq(1)
17
+
18
+ # Server meta info is stored in json format and encoded using utf-8 and base64
19
+ server_meta_info_json = Base64.strict_decode64(request_headers[0].value).force_encoding('utf-8')
20
+ server_meta_info = Worldline::Acquiring::SDK::JSON::DefaultMarshaller.instance.unmarshal(server_meta_info_json, MetadataProvider::ServerMetaInfo)
21
+
22
+ expect(server_meta_info.platform_identifier).to eq(metadata_provider.send(:get_platform_identifier))
23
+ expect(server_meta_info.sdk_identifier).to eq(metadata_provider.send(:get_sdk_identifier))
24
+ expect(server_meta_info.sdk_creator).to eq('Worldline')
25
+ expect(server_meta_info.shopping_cart_extension.creator).to eq(shopping_cart_extension.creator)
26
+ expect(server_meta_info.shopping_cart_extension.name).to eq(shopping_cart_extension.name)
27
+ expect(server_meta_info.shopping_cart_extension.version).to eq(shopping_cart_extension.version)
28
+ expect(server_meta_info.shopping_cart_extension.extension_id).to eq(shopping_cart_extension.extension_id)
29
+ end
30
+
31
+ it 'can give metadata_headers with a full shopping cart without an extension id' do
32
+ shopping_cart_extension = Worldline::Acquiring::SDK::Domain::ShoppingCartExtension.new('Worldline.creator', 'Extension', '1.0')
33
+ metadata_provider = MetadataProvider.new('Worldline', shopping_cart_extension: shopping_cart_extension)
34
+
35
+ request_headers = metadata_provider.metadata_headers
36
+ expect(request_headers.length).to eq(1)
37
+ expect(request_headers.length).to eq(1)
38
+
39
+ # Server meta info is stored in json format and encoded using utf-8 and base64
40
+ server_meta_info_json = Base64.strict_decode64(request_headers[0].value).force_encoding('utf-8')
41
+ server_meta_info = Worldline::Acquiring::SDK::JSON::DefaultMarshaller.instance.unmarshal(server_meta_info_json, MetadataProvider::ServerMetaInfo)
42
+
43
+ expect(server_meta_info.platform_identifier).to eq(metadata_provider.send(:get_platform_identifier))
44
+ expect(server_meta_info.sdk_identifier).to eq(metadata_provider.send(:get_sdk_identifier))
45
+ expect(server_meta_info.sdk_creator).to eq('Worldline')
46
+ expect(server_meta_info.shopping_cart_extension.creator).to eq(shopping_cart_extension.creator)
47
+ expect(server_meta_info.shopping_cart_extension.name).to eq(shopping_cart_extension.name)
48
+ expect(server_meta_info.shopping_cart_extension.version).to eq(shopping_cart_extension.version)
49
+ expect(server_meta_info.shopping_cart_extension.extension_id).to eq(shopping_cart_extension.extension_id)
50
+ end
51
+
52
+ it 'provides a server_meta_info header when no additional headers are provided' do
53
+ metadata_provider = MetadataProvider.new('Worldline')
54
+
55
+ request_headers = metadata_provider.metadata_headers
56
+ expect(request_headers.length).to eq(1)
57
+ expect(request_headers[0].name).to eq('X-WL-ServerMetaInfo')
58
+ expect(request_headers[0].value).to_not be_nil
59
+
60
+ # Server meta info is stored in json format and encoded using utf-8 and base64
61
+ server_meta_info_json = Base64.strict_decode64(request_headers[0].value).force_encoding('utf-8')
62
+ server_meta_info = Worldline::Acquiring::SDK::JSON::DefaultMarshaller.instance.unmarshal(server_meta_info_json, MetadataProvider::ServerMetaInfo)
63
+
64
+ expect(server_meta_info.platform_identifier).to eq(metadata_provider.send(:get_platform_identifier))
65
+ expect(server_meta_info.sdk_identifier).to eq(metadata_provider.send(:get_sdk_identifier))
66
+ expect(server_meta_info.sdk_creator).to eq('Worldline')
67
+ end
68
+
69
+ it 'provides a server_meta_info header and any additional headers provided' do
70
+ additional_headers = [RequestHeader.new('Header1', '&=$%'), RequestHeader.new('Header2', 'blah, blah'),
71
+ RequestHeader.new('Header3', 'foo')]
72
+ metadata_provider = MetadataProvider.new('Worldline', additional_request_headers: additional_headers)
73
+ request_headers = metadata_provider.metadata_headers
74
+
75
+ expect(request_headers.length).to eq(4)
76
+
77
+ i = 1
78
+ additional_headers.each do |header|
79
+ expect(request_headers[i]).to eq(header)
80
+ i += 1
81
+ end
82
+ end
83
+
84
+ it 'refuses headers marked as prohibited' do
85
+ MetadataProvider.prohibited_headers.each do |name|
86
+ additional_headers = [RequestHeader.new('Header1', 'Value1'),
87
+ RequestHeader.new(name, 'blood diamonds'),
88
+ RequestHeader.new('Header3', 'Value3')]
89
+ expect{MetadataProvider.new('Worldline', additional_request_headers: additional_headers)}
90
+ .to raise_error{|error| expect(error.message).to include(name)}
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,181 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+
4
+ CommunicatorConfiguration ||= Worldline::Acquiring::SDK::CommunicatorConfiguration
5
+
6
+ describe 'CommunicatorConfiguration' do
7
+
8
+ it 'can be constructed without a proxy' do
9
+ yaml = '---
10
+ acquiring.api.endpoint.host: api.preprod.acquiring.worldline-solutions.com
11
+ acquiring.api.authorizationType: OAuth2
12
+ acquiring.api.connectTimeout: 20
13
+ acquiring.api.socketTimeout: 10'
14
+ config = YAML.load(yaml)
15
+
16
+ communicator_config = CommunicatorConfiguration.new(properties: config)
17
+
18
+ expect(communicator_config.api_endpoint).to eq('https://api.preprod.acquiring.worldline-solutions.com')
19
+ expect(communicator_config.authorization_type).to eq('OAuth2')
20
+ expect(communicator_config.connect_timeout).to eq(20)
21
+ expect(communicator_config.socket_timeout).to eq(10)
22
+
23
+ expect(communicator_config.authorization_id).to be_nil
24
+ expect(communicator_config.authorization_secret).to be_nil
25
+ expect(communicator_config.proxy_configuration).to be_nil
26
+ expect(communicator_config.integrator).to be_nil
27
+ expect(communicator_config.shopping_cart_extension).to be_nil
28
+ end
29
+
30
+ it 'can be constructed with a proxy, without authentication' do
31
+ yaml = '---
32
+ acquiring.api.endpoint.host: api.preprod.acquiring.worldline-solutions.com
33
+ acquiring.api.authorizationType: OAuth2
34
+ acquiring.api.connectTimeout: 20
35
+ acquiring.api.socketTimeout: 10
36
+ acquiring.api.proxy.uri: http://proxy.example.org:3128'
37
+ config = YAML.load(yaml)
38
+
39
+ communicator_config = CommunicatorConfiguration.new(properties: config)
40
+ proxy_config = communicator_config.proxy_configuration
41
+
42
+ expect(communicator_config.api_endpoint).to eq('https://api.preprod.acquiring.worldline-solutions.com')
43
+ expect(communicator_config.authorization_type).to eq('OAuth2')
44
+ expect(communicator_config.connect_timeout).to eq(20)
45
+ expect(communicator_config.socket_timeout).to eq(10)
46
+
47
+ expect(communicator_config.authorization_id).to be_nil
48
+ expect(communicator_config.authorization_secret).to be_nil
49
+ expect(proxy_config).to be_truthy
50
+ expect(proxy_config.scheme).to eq('http')
51
+ expect(proxy_config.host).to eq('proxy.example.org')
52
+ expect(proxy_config.port).to eq(3128)
53
+ expect(proxy_config.username).to be_nil
54
+ expect(proxy_config.password).to be_nil
55
+ end
56
+
57
+ it 'can be constructed to authenticate to a proxy' do
58
+ yaml = '---
59
+ acquiring.api.endpoint.host: api.preprod.acquiring.worldline-solutions.com
60
+ acquiring.api.authorizationType: OAuth2
61
+ acquiring.api.connectTimeout: 20
62
+ acquiring.api.socketTimeout: 10
63
+ acquiring.api.proxy.uri: http://proxy.example.org:3128
64
+ acquiring.api.proxy.username: test-username
65
+ acquiring.api.proxy.password: test-password'
66
+ config = YAML.load(yaml)
67
+
68
+ communicator_config = CommunicatorConfiguration.new(properties: config)
69
+ proxy_config = communicator_config.proxy_configuration
70
+
71
+ expect(communicator_config.api_endpoint).to eq('https://api.preprod.acquiring.worldline-solutions.com')
72
+ expect(communicator_config.authorization_type).to eq('OAuth2')
73
+ expect(communicator_config.connect_timeout).to eq(20)
74
+ expect(communicator_config.socket_timeout).to eq(10)
75
+
76
+ expect(communicator_config.authorization_id).to be_nil
77
+ expect(communicator_config.authorization_secret).to be_nil
78
+ expect(proxy_config).to be_truthy
79
+ expect(proxy_config.scheme).to eq('http')
80
+ expect(proxy_config.host).to eq('proxy.example.org')
81
+ expect(proxy_config.port).to eq(3128)
82
+ expect(proxy_config.username).to eq('test-username')
83
+ expect(proxy_config.password).to eq('test-password')
84
+ end
85
+
86
+ it 'accepts a different number of maximum connections' do
87
+ yaml = '---
88
+ acquiring.api.endpoint.host: api.preprod.acquiring.worldline-solutions.com
89
+ acquiring.api.authorizationType: OAuth2
90
+ acquiring.api.connectTimeout: 20
91
+ acquiring.api.socketTimeout: 10
92
+ acquiring.api.maxConnections: 100'
93
+ config = YAML.load(yaml)
94
+
95
+ communicator_config = CommunicatorConfiguration.new(properties: config)
96
+
97
+ expect(communicator_config.api_endpoint).to eq('https://api.preprod.acquiring.worldline-solutions.com')
98
+ expect(communicator_config.authorization_type).to eq('OAuth2')
99
+ expect(communicator_config.connect_timeout).to eq(20)
100
+ expect(communicator_config.socket_timeout).to eq(10)
101
+ expect(communicator_config.max_connections).to eq(100)
102
+
103
+ expect(communicator_config.authorization_id).to be_nil
104
+ expect(communicator_config.authorization_secret).to be_nil
105
+ expect(communicator_config.proxy_configuration).to be_nil
106
+ end
107
+
108
+ it 'uses specific scheme to override default' do
109
+ yaml = '---
110
+ acquiring.api.endpoint.host: api.preprod.acquiring.worldline-solutions.com
111
+ acquiring.api.authorizationType: OAuth2
112
+ acquiring.api.connectTimeout: 20
113
+ acquiring.api.socketTimeout: 10
114
+ acquiring.api.endpoint.scheme: http'
115
+ config = YAML.load(yaml)
116
+
117
+ communicator_config = CommunicatorConfiguration.new(properties: config)
118
+
119
+ expect(communicator_config.api_endpoint).to eq('http://api.preprod.acquiring.worldline-solutions.com')
120
+ end
121
+
122
+ it 'uses specific port to override default' do
123
+ yaml = '---
124
+ acquiring.api.endpoint.host: api.preprod.acquiring.worldline-solutions.com
125
+ acquiring.api.authorizationType: OAuth2
126
+ acquiring.api.connectTimeout: 20
127
+ acquiring.api.socketTimeout: 10
128
+ acquiring.api.endpoint.port: 8080'
129
+ config = YAML.load(yaml)
130
+
131
+ communicator_config = CommunicatorConfiguration.new(properties: config)
132
+
133
+ expect(communicator_config.api_endpoint).to eq('https://api.preprod.acquiring.worldline-solutions.com:8080')
134
+ end
135
+
136
+ it 'uses specific scheme and port to override default' do
137
+ yaml = '---
138
+ acquiring.api.endpoint.host: api.preprod.acquiring.worldline-solutions.com
139
+ acquiring.api.authorizationType: OAuth2
140
+ acquiring.api.connectTimeout: 20
141
+ acquiring.api.socketTimeout: 10
142
+ acquiring.api.endpoint.scheme: http
143
+ acquiring.api.endpoint.port: 8080'
144
+ config = YAML.load(yaml)
145
+
146
+ communicator_config = CommunicatorConfiguration.new(properties: config)
147
+
148
+ expect(communicator_config.api_endpoint).to eq('http://api.preprod.acquiring.worldline-solutions.com:8080')
149
+ end
150
+
151
+ it 'stores shoppingCartExtension data' do
152
+ yaml = '---
153
+ acquiring.api.endpoint.host: api.preprod.acquiring.worldline-solutions.com
154
+ acquiring.api.authorizationType: OAuth2
155
+ acquiring.api.connectTimeout: 20
156
+ acquiring.api.socketTimeout: 10
157
+ acquiring.api.integrator: Worldline.Integrator
158
+ acquiring.api.shoppingCartExtension.creator: Worldline.Creator
159
+ acquiring.api.shoppingCartExtension.name: Worldline.ShoppingCarts
160
+ acquiring.api.shoppingCartExtension.version: 1.0
161
+ acquiring.api.shoppingCartExtension.extensionId: ExtensionId'
162
+ config = YAML.load(yaml)
163
+
164
+ communicator_config = CommunicatorConfiguration.new(properties: config)
165
+
166
+ expect(communicator_config.api_endpoint).to eq('https://api.preprod.acquiring.worldline-solutions.com')
167
+ expect(communicator_config.authorization_type).to eq('OAuth2')
168
+ expect(communicator_config.connect_timeout).to eq(20)
169
+ expect(communicator_config.socket_timeout).to eq(10)
170
+
171
+ expect(communicator_config.authorization_id).to be_nil
172
+ expect(communicator_config.authorization_secret).to be_nil
173
+ expect(communicator_config.proxy_configuration).to be_nil
174
+ expect(communicator_config.integrator).to eq('Worldline.Integrator')
175
+ expect(communicator_config.shopping_cart_extension).to be_truthy
176
+ expect(communicator_config.shopping_cart_extension.creator).to eq('Worldline.Creator')
177
+ expect(communicator_config.shopping_cart_extension.name).to eq('Worldline.ShoppingCarts')
178
+ expect(communicator_config.shopping_cart_extension.version).to eq('1.0')
179
+ expect(communicator_config.shopping_cart_extension.extension_id).to eq('ExtensionId')
180
+ end
181
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ require 'uri'
3
+
4
+ Communicator ||= Worldline::Acquiring::SDK::Communicator
5
+ Authenticator ||= Worldline::Acquiring::SDK::Authentication::Authenticator
6
+ DefaultMarshaller ||= Worldline::Acquiring::SDK::JSON::DefaultMarshaller
7
+ RequestParam ||= Worldline::Acquiring::SDK::Communication::RequestParam
8
+
9
+ describe Communicator do
10
+
11
+ let(:conn){conn = Connection.allocate} # Create fake (uninitialized) connection
12
+ let(:auth){auth = Authenticator.allocate} # Create fake (uninitialized) authenticator
13
+ let(:metadataProvider){metadata_provider = MetadataProvider.new("Worldline")}
14
+ let(:communicator){communicator = Communicator.new('https://api.preprod.acquiring.worldline-solutions.com', conn, auth, metadataProvider, DefaultMarshaller.instance)}
15
+ context 'to_absolute_uri()' do
16
+ it 'accepts a uri with or without a leading slash' do
17
+ uri1 = communicator.send(:to_absolute_uri, 'services/v1/100812/520000214/dcc-rates', [])
18
+ uri2 = communicator.send(:to_absolute_uri, '/services/v1/100812/520000214/dcc-rates', [])
19
+ # Ruby URI library adds port in HTTPS url's by default
20
+ expect(uri1.to_s).to eq('https://api.preprod.acquiring.worldline-solutions.com:443/services/v1/100812/520000214/dcc-rates')
21
+ expect(uri2.to_s).to eq('https://api.preprod.acquiring.worldline-solutions.com:443/services/v1/100812/520000214/dcc-rates')
22
+ end
23
+
24
+ it 'adds request parameters to the uri' do
25
+ request_params = [RequestParam.new('amount', '123'), RequestParam.new('source', 'USD'),
26
+ RequestParam.new('target', 'EUR'), RequestParam.new('dummy', 'é&%=')]
27
+
28
+ uri = communicator.send(:to_absolute_uri, 'services/v1/100812/520000214/dcc-rates', request_params)
29
+
30
+ expect(uri.to_s).to eq('https://api.preprod.acquiring.worldline-solutions.com:443/services/v1/100812/520000214/dcc-rates'\
31
+ '?amount=123&source=USD&target=EUR&dummy=%C3%A9%26%25%3D')
32
+ end
33
+ end
34
+ end