tilia-http 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +35 -0
  5. data/.simplecov +4 -0
  6. data/.travis.yml +3 -0
  7. data/CHANGELOG.sabre.md +235 -0
  8. data/CONTRIBUTING.md +25 -0
  9. data/Gemfile +18 -0
  10. data/Gemfile.lock +69 -0
  11. data/LICENSE +27 -0
  12. data/LICENSE.sabre +27 -0
  13. data/README.md +68 -0
  14. data/Rakefile +17 -0
  15. data/examples/asyncclient.rb +45 -0
  16. data/examples/basicauth.rb +39 -0
  17. data/examples/client.rb +20 -0
  18. data/examples/reverseproxy.rb +39 -0
  19. data/examples/stringify.rb +37 -0
  20. data/lib/tilia/http/auth/abstract_auth.rb +51 -0
  21. data/lib/tilia/http/auth/aws.rb +191 -0
  22. data/lib/tilia/http/auth/basic.rb +43 -0
  23. data/lib/tilia/http/auth/bearer.rb +37 -0
  24. data/lib/tilia/http/auth/digest.rb +187 -0
  25. data/lib/tilia/http/auth.rb +12 -0
  26. data/lib/tilia/http/client.rb +452 -0
  27. data/lib/tilia/http/client_exception.rb +15 -0
  28. data/lib/tilia/http/client_http_exception.rb +37 -0
  29. data/lib/tilia/http/http_exception.rb +21 -0
  30. data/lib/tilia/http/message.rb +241 -0
  31. data/lib/tilia/http/message_decorator_trait.rb +183 -0
  32. data/lib/tilia/http/message_interface.rb +154 -0
  33. data/lib/tilia/http/request.rb +235 -0
  34. data/lib/tilia/http/request_decorator.rb +160 -0
  35. data/lib/tilia/http/request_interface.rb +126 -0
  36. data/lib/tilia/http/response.rb +164 -0
  37. data/lib/tilia/http/response_decorator.rb +58 -0
  38. data/lib/tilia/http/response_interface.rb +36 -0
  39. data/lib/tilia/http/sapi.rb +165 -0
  40. data/lib/tilia/http/url_util.rb +70 -0
  41. data/lib/tilia/http/util.rb +51 -0
  42. data/lib/tilia/http/version.rb +9 -0
  43. data/lib/tilia/http.rb +416 -0
  44. data/test/http/auth/aws_test.rb +189 -0
  45. data/test/http/auth/basic_test.rb +60 -0
  46. data/test/http/auth/bearer_test.rb +47 -0
  47. data/test/http/auth/digest_test.rb +141 -0
  48. data/test/http/client_mock.rb +101 -0
  49. data/test/http/client_test.rb +331 -0
  50. data/test/http/message_decorator_test.rb +67 -0
  51. data/test/http/message_test.rb +163 -0
  52. data/test/http/request_decorator_test.rb +87 -0
  53. data/test/http/request_test.rb +132 -0
  54. data/test/http/response_decorator_test.rb +28 -0
  55. data/test/http/response_test.rb +38 -0
  56. data/test/http/sapi_mock.rb +12 -0
  57. data/test/http/sapi_test.rb +133 -0
  58. data/test/http/url_util_test.rb +155 -0
  59. data/test/http/util_test.rb +186 -0
  60. data/test/http_test.rb +102 -0
  61. data/test/test_helper.rb +6 -0
  62. data/tilia-http.gemspec +18 -0
  63. metadata +192 -0
@@ -0,0 +1,141 @@
1
+ require 'digest'
2
+ require 'test_helper'
3
+
4
+ module Tilia
5
+ module Http
6
+ class DigestTest < Minitest::Test
7
+ REALM = 'SabreDAV unittest'
8
+
9
+ def setup
10
+ @response = Response.new
11
+ @request = Request.new
12
+ @auth = Auth::Digest.new(REALM, @request, @response)
13
+ end
14
+
15
+ def uniqid
16
+ Digest::SHA1.hexdigest((Time.now.to_f + rand).to_s)[0..14]
17
+ end
18
+
19
+ def get_server_tokens(qop = Auth::Digest::QOP_AUTH)
20
+ @auth.require_login
21
+
22
+ case qop
23
+ when Auth::Digest::QOP_AUTH
24
+ qopstr = 'auth'
25
+ when Auth::Digest::QOP_AUTHINT
26
+ qopstr = 'auth-int'
27
+ else
28
+ qopstr = 'auth,auth-int'
29
+ end
30
+
31
+ test_result = @response.header('WWW-Authenticate') =~ /Digest realm="#{REALM}",qop="#{qopstr}",nonce="([0-9a-f]*)",opaque="([0-9a-f]*)"/
32
+
33
+ assert(test_result, "The WWW-Authenticate response didn't match our pattern. We received: #{@response.header('WWW-Authenticate')}")
34
+
35
+ nonce = Regexp.last_match[1]
36
+ opaque = Regexp.last_match[2]
37
+
38
+ # Reset our environment
39
+ setup
40
+ @auth.qop = qop
41
+
42
+ [nonce, opaque]
43
+ end
44
+
45
+ def test_digest
46
+ (nonce, opaque) = get_server_tokens
47
+
48
+ username = 'admin'
49
+ password = '12345'
50
+ nc = '00002'
51
+ cnonce = uniqid
52
+
53
+ digest_hash = Digest::MD5.hexdigest(
54
+ "#{Digest::MD5.hexdigest("#{username}:#{REALM}:#{password}")}:#{nonce}:#{nc}:#{cnonce}:auth:#{Digest::MD5.hexdigest('GET:/')}"
55
+ )
56
+
57
+ @request.method = 'GET'
58
+ @request.update_header('Authorization', "Digest username=\"#{username}\", realm=\"#{REALM}\", nonce=\"#{nonce}\", uri=\"/\", response=\"#{digest_hash}\", opaque=\"#{opaque}\", qop=auth,nc=#{nc},cnonce=\"#{cnonce}\"")
59
+
60
+ @auth.init
61
+
62
+ assert_equal(username, @auth.username)
63
+ assert_equal(REALM, @auth.realm)
64
+ assert(@auth.validate_a1(Digest::MD5.hexdigest("#{username}:#{REALM}:#{password}")), 'Authentication is deemed invalid through validateA1')
65
+ assert(@auth.validate_password(password), 'Authentication is deemed invalid through validatepassword')
66
+ end
67
+
68
+ def test_invalid_digest
69
+ (nonce, opaque) = get_server_tokens
70
+
71
+ username = 'admin'
72
+ password = '12345'
73
+ nc = '00002'
74
+ cnonce = uniqid
75
+
76
+ digest_hash = Digest::MD5.hexdigest(
77
+ "#{Digest::MD5.hexdigest("#{username}:#{REALM}:#{password}")}:#{nonce}:#{nc}:#{cnonce}:auth:#{Digest::MD5.hexdigest('GET:/')}"
78
+ )
79
+
80
+ @request.method = 'GET'
81
+ @request.update_header('Authorization', "Digest username=\"#{username}\", realm=\"#{REALM}\", nonce=\"#{nonce}\", uri=\"/\", response=\"#{digest_hash}\", opaque=\"#{opaque}\", qop=auth,nc=#{nc},cnonce=\"#{cnonce}\"")
82
+
83
+ @auth.init
84
+
85
+ refute(@auth.validate_a1(Digest::MD5.hexdigest("#{username}:#{REALM}:#{password}randomness")), 'Authentication is deemed invalid through validateA1')
86
+ end
87
+
88
+ def test_invalid_digest2
89
+ @request.method = 'GET'
90
+ @request.update_header('Authorization', 'basic blablabla')
91
+
92
+ @auth.init
93
+ refute(@auth.validate_a1(Digest::MD5.hexdigest('user:realm:password')))
94
+ end
95
+
96
+ def test_digest_auth_int
97
+ @auth.qop = Auth::Digest::QOP_AUTHINT
98
+ (nonce, opaque) = get_server_tokens(Auth::Digest::QOP_AUTHINT)
99
+
100
+ username = 'admin'
101
+ password = '12345'
102
+ nc = '00003'
103
+ cnonce = uniqid
104
+
105
+ digest_hash = Digest::MD5.hexdigest(
106
+ "#{Digest::MD5.hexdigest("#{username}:#{REALM}:#{password}")}:#{nonce}:#{nc}:#{cnonce}:auth-int:#{Digest::MD5.hexdigest('POST:/:' + Digest::MD5.hexdigest('body'))}"
107
+ )
108
+
109
+ @request.method = 'POST'
110
+ @request.update_header('Authorization', "Digest username=\"#{username}\", realm=\"#{REALM}\", nonce=\"#{nonce}\", uri=\"/\", response=\"#{digest_hash}\", opaque=\"#{opaque}\", qop=auth-int,nc=#{nc},cnonce=\"#{cnonce}\"")
111
+ @request.body = 'body'
112
+
113
+ @auth.init
114
+
115
+ assert(@auth.validate_a1(Digest::MD5.hexdigest("#{username}:#{REALM}:#{password}")), 'Authentication is deemed invalid through validateA1')
116
+ end
117
+
118
+ def test_digest_auth_both
119
+ @auth.qop = Auth::Digest::QOP_AUTHINT | Auth::Digest::QOP_AUTH
120
+ (nonce, opaque) = get_server_tokens(Auth::Digest::QOP_AUTHINT | Auth::Digest::QOP_AUTH)
121
+
122
+ username = 'admin'
123
+ password = '12345'
124
+ nc = '00003'
125
+ cnonce = uniqid
126
+
127
+ digest_hash = Digest::MD5.hexdigest(
128
+ "#{Digest::MD5.hexdigest("#{username}:#{REALM}:#{password}")}:#{nonce}:#{nc}:#{cnonce}:auth-int:#{Digest::MD5.hexdigest('POST:/:' + Digest::MD5.hexdigest('body'))}"
129
+ )
130
+
131
+ @request.method = 'POST'
132
+ @request.update_header('Authorization', "Digest username=\"#{username}\", realm=\"#{REALM}\", nonce=\"#{nonce}\", uri=\"/\", response=\"#{digest_hash}\", opaque=\"#{opaque}\", qop=auth-int,nc=#{nc},cnonce=\"#{cnonce}\"")
133
+ @request.body = 'body'
134
+
135
+ @auth.init
136
+
137
+ assert(@auth.validate_a1(Digest::MD5.hexdigest("#{username}:#{REALM}:#{password}")), 'Authentication is deemed invalid through validateA1')
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,101 @@
1
+ # TODO: document
2
+ module Tilia
3
+ module Http
4
+ class ClientMock < Client
5
+ # RUBY: attr_accessor :persisted_settings
6
+
7
+ # Making this method public.
8
+ #
9
+ # We are also going to persist all settings this method generates. While
10
+ # the underlying object doesn't behave exactly the same, it helps us
11
+ # simulate what curl does internally, and helps us identify problems with
12
+ # settings that are set by _some_ methods and not correctly reset by other
13
+ # methods after subsequent use.
14
+ # forces
15
+ def create_curl_settings_array(request)
16
+ settings = super(request)
17
+ settings = @persisted_settings.merge(settings)
18
+ @persisted_settings = settings
19
+ settings
20
+ end
21
+
22
+ # Making this method public.
23
+ def parse_curl_result(curl_handle)
24
+ super(curl_handle)
25
+ end
26
+
27
+ # This method is responsible for performing a single request.
28
+ #
29
+ # @param RequestInterface request
30
+ # @return [ResponseInterface]
31
+ def do_request(request)
32
+ response = nil
33
+
34
+ do_request_arguments = DoRequestArguments.new(request, response)
35
+ emit('doRequest', [do_request_arguments])
36
+ (request, response) = do_request_arguments.to_a
37
+
38
+ # If nothing modified response, we're using the default behavior.
39
+ if response.nil?
40
+ super(request)
41
+ else
42
+ response
43
+ end
44
+ end
45
+
46
+ protected
47
+
48
+ # Returns a bunch of information about a curl request.
49
+ #
50
+ # This method exists so it can easily be overridden and mocked.
51
+ #
52
+ # @param resource curl_handle
53
+ # @return array
54
+ def curl_stuff(curl_handle)
55
+ to_return = nil
56
+ curl_stuff_arguments = CurlStuffArguments.new(to_return)
57
+ emit('curlStuff', [curl_stuff_arguments])
58
+ (to_return,) = curl_stuff_arguments.to_a
59
+
60
+ # If nothing modified return, we're using the default behavior.
61
+ if to_return.nil?
62
+ super(curl_handle)
63
+ else
64
+ to_return
65
+ end
66
+ end
67
+
68
+ # Calls curl_exec
69
+ #
70
+ # This method exists so it can easily be overridden and mocked.
71
+ #
72
+ # @param resource curl_handle
73
+ # @return [String]
74
+ def curl_exec(curl_handle, request)
75
+ to_return = nil
76
+ curl_exec_arguments = CurlExecArguments.new(to_return)
77
+ emit('curlExec', [curl_exec_arguments])
78
+ (to_return,) = curl_exec_arguments.to_a
79
+
80
+ # If nothing modified return, we're using the default behavior.
81
+ if to_return.nil?
82
+ super(curl_handle, request)
83
+ else
84
+ to_return
85
+ end
86
+ end
87
+
88
+ public
89
+
90
+ # TODO: document
91
+ def initialize
92
+ @persisted_settings = {}
93
+ super
94
+ end
95
+
96
+ DoRequestArguments = Struct.new(:request, :response)
97
+ CurlStuffArguments = Struct.new(:return)
98
+ CurlExecArguments = Struct.new(:curl_handle)
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,331 @@
1
+ require 'test_helper'
2
+ require 'stringio'
3
+ require 'http/client_mock'
4
+
5
+ module Tilia
6
+ module Http
7
+ class ClientTest < Minitest::Test
8
+ # it 'testCreateCurlSettingsArrayGET' do
9
+ # client = ClientMock.new
10
+ # client.add_curl_setting(Curl::CURLOPT_POSTREDIR, 0)
11
+ #
12
+ # request = Request.new('GET', 'http://example.org/', { 'X-Foo' => 'bar' })
13
+ #
14
+ # settings = {
15
+ # Curl::CURLOPT_HEADER => true,
16
+ # Curl::CURLOPT_POSTREDIR => 0,
17
+ # :CURLOPT_HTTPHEADER => ['X-Foo: bar'],
18
+ # Curl::CURLOPT_NOBODY => false,
19
+ # Curl::CURLOPT_URL => 'http://example.org/',
20
+ # Curl::CURLOPT_CUSTOMREQUEST => 'GET',
21
+ # Curl::CURLOPT_POSTFIELDS => '',
22
+ # :CURLOPT_PUT => false
23
+ # }
24
+ #
25
+ # assert_equal(settings, client.create_curl_settings_array(request))
26
+ # end
27
+ #
28
+ # it 'testCreateCurlSettingsArrayHEAD' do
29
+ # client = ClientMock.new
30
+ # request = Request.new('HEAD', 'http://example.org/', {'X-Foo' => 'bar'})
31
+ #
32
+ # settings = {
33
+ # Curl::CURLOPT_HEADER => true,
34
+ # Curl::CURLOPT_NOBODY => true,
35
+ # Curl::CURLOPT_CUSTOMREQUEST => 'HEAD',
36
+ # :CURLOPT_HTTPHEADER => ['X-Foo: bar'],
37
+ # Curl::CURLOPT_URL => 'http://example.org/',
38
+ # Curl::CURLOPT_POSTFIELDS => '',
39
+ # :CURLOPT_PUT => false
40
+ # }
41
+ #
42
+ # assert_equal(settings, client.create_curl_settings_array(request))
43
+ # end
44
+ #
45
+ # it 'testCreateCurlSettingsArrayGETAfterHEAD' do
46
+ # client = ClientMock.new
47
+ # request = Request.new('HEAD', 'http://example.org/', {'X-Foo' => 'bar'})
48
+ #
49
+ # # Parsing the settings for this method, and discarding the result.
50
+ # # This will cause the client to automatically persist previous
51
+ # # settings and will help us detect problems.
52
+ # client.create_curl_settings_array(request)
53
+ #
54
+ # # This is the real request.
55
+ # request = Request.new('GET', 'http://example.org/', {'X-Foo' => 'bar'})
56
+ #
57
+ # settings = {
58
+ # Curl::CURLOPT_CUSTOMREQUEST => 'GET',
59
+ # Curl::CURLOPT_HEADER => true,
60
+ # :CURLOPT_HTTPHEADER => ['X-Foo: bar'],
61
+ # Curl::CURLOPT_NOBODY => false,
62
+ # Curl::CURLOPT_URL => 'http://example.org/',
63
+ # Curl::CURLOPT_POSTFIELDS => '',
64
+ # :CURLOPT_PUT => false
65
+ # }
66
+ #
67
+ # assert_equal(settings, client.create_curl_settings_array(request))
68
+ # end
69
+ #
70
+ # it 'testCreateCurlSettingsArrayPUTStream' do
71
+ # pending
72
+ # client = ClientMock.new
73
+ #
74
+ # h = StringIO.new
75
+ # h.write('booh')
76
+ # request = Request.new('PUT', 'http://example.org/', {'X-Foo' => 'bar'}, h)
77
+ #
78
+ # settings = {
79
+ # Curl::CURLOPT_HEADER => true,
80
+ # :CURLOPT_PUT => true,
81
+ # :CURLOPT_INFILE => h,
82
+ # Curl::CURLOPT_NOBODY => false,
83
+ # Curl::CURLOPT_CUSTOMREQUEST => 'PUT',
84
+ # :CURLOPT_HTTPHEADER => ['X-Foo: bar'],
85
+ # Curl::CURLOPT_URL => 'http://example.org/'
86
+ # }
87
+ #
88
+ # assert_equal(settings, client.create_curl_settings_array(request))
89
+ # end
90
+ #
91
+ # it 'testCreateCurlSettingsArrayPUTString' do
92
+ # client = ClientMock.new
93
+ # request = Request.new('PUT', 'http://example.org/', {'X-Foo' => 'bar'}, 'boo')
94
+ #
95
+ # settings = {
96
+ # Curl::CURLOPT_HEADER => true,
97
+ # Curl::CURLOPT_NOBODY => false,
98
+ # Curl::CURLOPT_POSTFIELDS => 'boo',
99
+ # Curl::CURLOPT_CUSTOMREQUEST => 'PUT',
100
+ # :CURLOPT_HTTPHEADER => ['X-Foo: bar'],
101
+ # Curl::CURLOPT_URL => 'http://example.org/'
102
+ # }
103
+ #
104
+ # assert_equal(settings, client.create_curl_settings_array(request))
105
+ # end
106
+
107
+ def test_send
108
+ client = ClientMock.new
109
+ request = Request.new('GET', 'http://example.org/')
110
+
111
+ response = nil
112
+ client.on(
113
+ 'doRequest',
114
+ lambda do |_|
115
+ response = Response.new(200)
116
+ end
117
+ )
118
+
119
+ response = client.send(request)
120
+
121
+ assert_equal(200, response.status)
122
+ end
123
+
124
+ def test_send_client_error
125
+ client = ClientMock.new
126
+ request = Request.new('GET', 'http://example.org/')
127
+
128
+ client.on(
129
+ 'doRequest',
130
+ lambda do |_|
131
+ fail ClientException, 'aaah'
132
+ end
133
+ )
134
+
135
+ called = false
136
+ client.on(
137
+ 'exception',
138
+ lambda do |_a, _b, _c, _d|
139
+ called = true
140
+ end
141
+ )
142
+
143
+ assert_raises(ClientException) { client.send(request) }
144
+
145
+ assert(called)
146
+ end
147
+
148
+ def test_send_http_error
149
+ client = ClientMock.new
150
+ request = Request.new('GET', 'http://example.org/')
151
+
152
+ client.on(
153
+ 'doRequest',
154
+ lambda do |args|
155
+ args.response = Response.new(404)
156
+ end
157
+ )
158
+
159
+ called = 0
160
+ client.on(
161
+ 'error',
162
+ lambda do |_a, _b, _c, _d|
163
+ called += 1
164
+ end
165
+ )
166
+ client.on(
167
+ 'error:404',
168
+ lambda do |_a, _b, _c, _d|
169
+ called += 1
170
+ end
171
+ )
172
+
173
+ client.send(request)
174
+ assert_equal(2, called)
175
+ end
176
+
177
+ def test_send_retry
178
+ client = ClientMock.new
179
+ request = Request.new('GET', 'http://example.org/')
180
+
181
+ called = 0
182
+ client.on(
183
+ 'doRequest',
184
+ lambda do |args|
185
+ called += 1
186
+ if called < 3
187
+ args.response = Response.new(404)
188
+ else
189
+ args.response = Response.new(200)
190
+ end
191
+ end
192
+ )
193
+
194
+ error_called = 0
195
+ client.on(
196
+ 'error',
197
+ lambda do |_a, _b, do_retry, _d|
198
+ error_called += 1
199
+ do_retry.value = true
200
+ end
201
+ )
202
+
203
+ response = client.send(request)
204
+ assert_equal(3, called)
205
+ assert_equal(2, error_called)
206
+ assert_equal(200, response.status)
207
+ end
208
+
209
+ def test_http_error_exception
210
+ client = ClientMock.new
211
+ client.throw_exceptions = true
212
+ request = Request.new('GET', 'http://example.org/')
213
+
214
+ client.on(
215
+ 'doRequest',
216
+ lambda do |args|
217
+ args.response = Response.new(404)
218
+ end
219
+ )
220
+
221
+ error = assert_raises(Exception) { client.send(request) }
222
+ assert_kind_of(ClientHttpException, error)
223
+ assert_equal(404, error.http_status)
224
+ assert_kind_of(Response, error.response)
225
+ end
226
+
227
+ # it 'testParseCurlResult' do
228
+ # client = ClientMock.new
229
+ # client.on(
230
+ # 'curlStuff',
231
+ # lambda do |args|
232
+ # args.return = [
233
+ # {
234
+ # 'header_size' => 33,
235
+ # 'http_code' => 200
236
+ # },
237
+ # 0,
238
+ # ''
239
+ # ]
240
+ # end
241
+ # )
242
+ #
243
+ # body = "HTTP/1.1 200 OK\r\nHeader1:Val1\r\n\r\nFoo"
244
+ # result = client.parse_curl_result(body, 'foobar')
245
+ #
246
+ # assert_equal(Client::STATUS_SUCCESS, result['status'])
247
+ # assert_equal(200, result['http_code'])
248
+ # assert_equal(200, result['response'].status)
249
+ # assert_equal({ 'Header1' => ['Val1'] }, result['response'].headers)
250
+ # assert_equal('Foo', result['response'].body_as_string)
251
+ # end
252
+ #
253
+ # it 'testParseCurlError' do
254
+ # client = ClientMock.new
255
+ # client.on(
256
+ # 'curlStuff',
257
+ # lambda do |args|
258
+ # args.return = [
259
+ # { },
260
+ # 1,
261
+ # 'Curl error'
262
+ # ]
263
+ # end
264
+ # )
265
+ #
266
+ # body = "HTTP/1.1 200 OK\r\nHeader1:Val1\r\n\r\nFoo"
267
+ # result = client.parse_curl_result(body, 'foobar')
268
+ #
269
+ # assert_equal(Client::STATUS_CURLERROR, result['status'])
270
+ # assert_equal(1, result['curl_errno'])
271
+ # assert_equal('Curl error', result['curl_errmsg'])
272
+ # end
273
+ #
274
+ # it 'testDoRequest' do
275
+ # client = ClientMock.new
276
+ # request = Request.new('GET', 'http://example.org/')
277
+ # client.on(
278
+ # 'curlExec',
279
+ # lambda do |args|
280
+ # args.curl_handle = "HTTP/1.1 200 OK\r\nHeader1:Val1\r\n\r\nFoo"
281
+ # end
282
+ # )
283
+ #
284
+ # client.on(
285
+ # 'curlStuff',
286
+ # lambda do |args|
287
+ # args.return = [
288
+ # {
289
+ # 'header_size' => 33,
290
+ # 'http_code' => 200
291
+ # },
292
+ # 0,
293
+ # ''
294
+ # ]
295
+ # end
296
+ # )
297
+ # response = client.do_request(request)
298
+ # assert_equal(200, response.status)
299
+ # assert_equal({ 'Header1' => ['Val1'] }, response.headers)
300
+ # assert_equal('Foo', response.body_as_string)
301
+ # end
302
+ #
303
+ # it 'testDoRequestCurlError' do
304
+ # client = ClientMock.new
305
+ # request = Request.new('GET', 'http://example.org/')
306
+ # client.on(
307
+ # 'curlExec',
308
+ # lambda do |args|
309
+ # args.curl_handle = ''
310
+ # end
311
+ # )
312
+ #
313
+ # client.on(
314
+ # 'curlStuff',
315
+ # lambda do |args|
316
+ # args.return = [
317
+ # { },
318
+ # 1,
319
+ # 'Curl error'
320
+ # ]
321
+ # end
322
+ # )
323
+ #
324
+ # expect { response = client.do_request(request) }.to raise_error ClientException do |error|
325
+ # assert_equal(1, error.code)
326
+ # assert_equal('Curl error', error.message)
327
+ # end
328
+ # end
329
+ end
330
+ end
331
+ end
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+
3
+ module Tilia
4
+ module Http
5
+ class MessageDecoratorTest < Minitest::Test
6
+ def setup
7
+ @inner = Tilia::Http::Request.new
8
+ @outer = Tilia::Http::RequestDecorator.new(@inner)
9
+ end
10
+
11
+ def test_body
12
+ @outer.body = 'foo'
13
+ assert_equal('foo', @inner.body_as_stream.readlines.join(''))
14
+ assert_equal('foo', @outer.body_as_stream.readlines.join(''))
15
+ assert_equal('foo', @inner.body_as_string)
16
+ assert_equal('foo', @outer.body_as_string)
17
+ assert_equal('foo', @inner.body)
18
+ assert_equal('foo', @outer.body)
19
+ end
20
+
21
+ def test_headers
22
+ @outer.update_headers('a' => 'b')
23
+
24
+ assert_equal({ 'a' => ['b'] }, @inner.headers)
25
+ assert_equal({ 'a' => ['b'] }, @outer.headers)
26
+
27
+ @outer.update_headers('c' => 'd')
28
+
29
+ assert_equal({ 'a' => ['b'], 'c' => ['d'] }, @inner.headers)
30
+ assert_equal({ 'a' => ['b'], 'c' => ['d'] }, @outer.headers)
31
+
32
+ @outer.add_headers('e' => 'f')
33
+
34
+ assert_equal({ 'a' => ['b'], 'c' => ['d'], 'e' => ['f'] }, @inner.headers)
35
+ assert_equal({ 'a' => ['b'], 'c' => ['d'], 'e' => ['f'] }, @outer.headers)
36
+ end
37
+
38
+ def test_header
39
+ refute(@outer.header?('a'))
40
+ refute(@inner.header?('a'))
41
+ @outer.update_header('a', 'c')
42
+ assert(@outer.header?('a'))
43
+ assert(@inner.header?('a'))
44
+
45
+ assert_equal('c', @inner.header('A'))
46
+ assert_equal('c', @outer.header('A'))
47
+
48
+ @outer.add_header('A', 'd')
49
+
50
+ assert_equal(['c', 'd'], @inner.header_as_array('A'))
51
+ assert_equal(['c', 'd'], @outer.header_as_array('A'))
52
+
53
+ @outer.remove_header('a')
54
+
55
+ assert_nil(@inner.header('A'))
56
+ assert_nil(@outer.header('A'))
57
+ end
58
+
59
+ def test_http_version
60
+ @outer.http_version = '1.0'
61
+
62
+ assert_equal('1.0', @inner.http_version)
63
+ assert_equal('1.0', @outer.http_version)
64
+ end
65
+ end
66
+ end
67
+ end