tilia-http 4.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 (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