httpkit 0.6.0.pre.3 → 0.6.0.pre.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +15 -0
  2. data/.rspec +0 -1
  3. data/.travis.yml +5 -4
  4. data/Gemfile +0 -2
  5. data/Gemfile.devtools +27 -22
  6. data/README.md +11 -13
  7. data/config/flay.yml +2 -2
  8. data/config/flog.yml +1 -1
  9. data/config/reek.yml +11 -5
  10. data/config/rubocop.yml +47 -5
  11. data/examples/echo_server.rb +2 -2
  12. data/examples/getting_started.rb +16 -10
  13. data/httpkit.gemspec +5 -4
  14. data/lib/httpkit.rb +15 -5
  15. data/lib/httpkit/body.rb +44 -33
  16. data/lib/httpkit/client.rb +52 -23
  17. data/lib/httpkit/client/body_handler.rb +21 -0
  18. data/lib/httpkit/client/{keep_alive.rb → keep_alive_handler.rb} +1 -1
  19. data/lib/httpkit/client/mandatory_handler.rb +29 -0
  20. data/lib/httpkit/client/{timeouts.rb → timeouts_handler.rb} +1 -1
  21. data/lib/httpkit/connection/eventmachine.rb +4 -4
  22. data/lib/httpkit/request.rb +46 -10
  23. data/lib/httpkit/response.rb +37 -5
  24. data/lib/httpkit/serializer.rb +33 -25
  25. data/lib/httpkit/server.rb +14 -19
  26. data/lib/httpkit/server/body_handler.rb +25 -0
  27. data/lib/httpkit/server/{keep_alive.rb → keep_alive_handler.rb} +22 -13
  28. data/lib/httpkit/server/mandatory_handler.rb +23 -0
  29. data/lib/httpkit/server/{timeouts.rb → timeouts_handler.rb} +1 -1
  30. data/lib/httpkit/support/handler_manager.rb +8 -5
  31. data/lib/httpkit/support/message.rb +28 -15
  32. data/lib/httpkit/version.rb +1 -1
  33. data/spec/integration/keep_alive_spec.rb +6 -7
  34. data/spec/integration/smoke_spec.rb +4 -4
  35. data/spec/integration/streaming_spec.rb +2 -3
  36. data/spec/integration/timeouts_spec.rb +6 -6
  37. data/spec/shared/integration/server_client_pair.rb +1 -1
  38. data/spec/spec_helper.rb +3 -2
  39. data/spec/support/handler.rb +1 -1
  40. data/spec/support/helper.rb +6 -4
  41. data/spec/unit/body_spec.rb +6 -0
  42. data/spec/unit/client/keep_alive_handler_spec.rb +6 -0
  43. data/spec/unit/client/mandatory_handler_spec.rb +31 -0
  44. data/spec/unit/client/timeouts_handler_spec.rb +6 -0
  45. data/spec/unit/client_spec.rb +83 -34
  46. data/spec/unit/connection/eventmachine_spec.rb +12 -13
  47. data/spec/unit/httpkit_spec.rb +65 -24
  48. data/spec/unit/promise_spec.rb +1 -1
  49. data/spec/unit/request_spec.rb +2 -10
  50. data/spec/unit/response_spec.rb +7 -15
  51. data/spec/unit/serializer_spec.rb +83 -0
  52. data/spec/unit/server/{keep_alive_spec.rb → keep_alive_handler_spec.rb} +5 -2
  53. data/spec/unit/server/mandatory_handler_spec.rb +30 -0
  54. data/spec/unit/server/timeouts_handler_spec.rb +6 -0
  55. data/spec/unit/server_spec.rb +26 -32
  56. data/spec/unit/support/handler_manager_spec.rb +38 -7
  57. data/spec/unit/support/message_spec.rb +45 -20
  58. metadata +57 -36
  59. data/lib/httpkit/serializer/encoding.rb +0 -43
@@ -2,7 +2,7 @@
2
2
 
3
3
  shared_context :server_client_pair do
4
4
  let(:server_config) { { handlers: [SpecHandler.new] } }
5
- let(:client_config) { {} }
5
+ let(:client_config) { { handlers: [] } }
6
6
  let(:interceptor) { double('interceptor') }
7
7
 
8
8
  let(:server_and_client) do
data/spec/spec_helper.rb CHANGED
@@ -23,6 +23,7 @@ require 'weakref'
23
23
  require 'awesome_print'
24
24
 
25
25
  require 'devtools/spec_helper'
26
+ require 'rspec/its'
26
27
 
27
28
  RSpec.configure do |config|
28
29
  config.include(SpecHelper)
@@ -30,7 +31,7 @@ RSpec.configure do |config|
30
31
  config.around do |example|
31
32
  if example.metadata[:reactor]
32
33
  EM.run do
33
- EM.add_timer(0.5) { raise 'Example timed out' }
34
+ EM.add_timer(0.25) { raise 'Example timed out' }
34
35
 
35
36
  Fiber.new do
36
37
  example.call
@@ -39,7 +40,7 @@ RSpec.configure do |config|
39
40
  end.resume
40
41
  end
41
42
  else
42
- Timeout.timeout(0.5) { example.call }
43
+ Timeout.timeout(0.25) { example.call }
43
44
  end
44
45
  end
45
46
  end
@@ -39,7 +39,7 @@ class SpecHandler
39
39
  SpecHelper.defer do
40
40
  %w[foo bar baz].each do |chunk|
41
41
  SpecHelper.tick(2)
42
- response.body.closed.progress(chunk)
42
+ response.body.write(chunk)
43
43
  end
44
44
  response.close
45
45
  end
@@ -24,16 +24,18 @@ module SpecHelper
24
24
  end
25
25
  module_function :defer
26
26
 
27
- def open_request(http_method = :get, uri = '/', headers = {})
28
- HTTPkit::Request.new(http_method, uri, headers, HTTPkit::Body.new)
27
+ def open_request(http_method = :get, uri = '/', headers = {}, body = nil,
28
+ http_version = 1.1)
29
+ HTTPkit::Request.new(http_method, uri, headers, body,
30
+ http_version)
29
31
  end
30
32
 
31
33
  def closed_request(*args)
32
34
  open_request(*args).tap(&:close)
33
35
  end
34
36
 
35
- def open_response(status = 200, headers = {})
36
- HTTPkit::Response.new(status, headers, HTTPkit::Body.new)
37
+ def open_response(status = 200, headers = {}, body = nil, http_version = 1.1)
38
+ HTTPkit::Response.new(status, headers, body, http_version)
37
39
  end
38
40
 
39
41
  def closed_response(*args)
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Body do
6
+ end
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Client::KeepAliveHandler do
6
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Client::MandatoryHandler do
6
+ describe '#perform' do
7
+ let(:handler) { described_class.new }
8
+ let(:request) { HTTPkit::Request.new(:get, '/', headers) }
9
+ let(:headers) { {} }
10
+
11
+ subject! do
12
+ handler.setup({ address: 'example.net', port: 80 }, nil, nil)
13
+ handler.perform(request) { |req| @request = req }
14
+ end
15
+
16
+ it 'sets User-Agent and Host headers' do
17
+ expect(@request.headers['User-Agent'])
18
+ .to eq("httpkit/#{HTTPkit::VERSION}")
19
+ expect(@request.headers['Host']).to eq('example.net:80')
20
+ end
21
+
22
+ describe 'with User-Agent or Host header set to anything' do
23
+ let(:headers) { { 'User-Agent' => nil, 'Host' => nil } }
24
+
25
+ it 'does not override' do
26
+ expect(@request.headers['User-Agent']).to be(nil)
27
+ expect(@request.headers['Host']).to be(nil)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe HTTPkit::Client::TimeoutsHandler do
6
+ end
@@ -31,21 +31,53 @@ describe HTTPkit::Client do
31
31
  end
32
32
  end
33
33
 
34
+ describe '.request' do
35
+ let(:arg) { double }
36
+ let(:uri) { 'http://localhost:3000' }
37
+
38
+ let(:options) { { address: 'localhost', port: 3000 } }
39
+ let(:client) { double }
40
+ let(:response) { double }
41
+
42
+ before do
43
+ allow(described_class).to receive(:start).with(options) { client }
44
+ allow(client).to receive(:request).with(arg, uri, arg, arg) { response }
45
+ end
46
+
47
+ subject { described_class.request(arg, uri, arg, arg) }
48
+
49
+ it 'starts a client and performs the request' do
50
+ expect(subject).to be(response)
51
+ end
52
+ end
53
+
34
54
  describe '#initialize' do
55
+ let(:on_message) { client.method(:receive) }
56
+ let(:teadown) { client.method(:teardown) }
57
+
35
58
  subject! { client }
36
59
 
37
60
  its(:config) { should be(config) }
38
61
 
39
- specify do
40
- expect(connection).to have_received(:on_message=)
41
- .with(subject.method(:receive))
42
- expect(connection.closed).to have_received(:then)
43
- .with(subject.method(:teardown), subject.method(:teardown))
62
+ it 'wires up #receive and #teardown' do
63
+ expect(connection).to have_received(:on_message=).with(on_message)
64
+ expect(connection.closed).to have_received(:then).with(teadown, teadown)
44
65
  end
45
66
 
46
- specify do
47
- expect(handler).to have_received(:setup)
48
- .with(config, subject, connection)
67
+ it 'sets up handlers' do
68
+ expect(handler).to have_received(:setup).with(config, client, connection)
69
+ expect(config[:handlers].first).to be(handler)
70
+ end
71
+
72
+ describe 'without handlers' do
73
+ let(:config) { {} }
74
+
75
+ it 'adds the mandatory and body handlers' do
76
+ expect(config[:handlers][0])
77
+ .to be_a(HTTPkit::Client::MandatoryHandler)
78
+ expect(config[:handlers][1])
79
+ .to be_a(HTTPkit::Client::BodyHandler)
80
+ end
49
81
  end
50
82
  end
51
83
 
@@ -58,21 +90,21 @@ describe HTTPkit::Client do
58
90
 
59
91
  before do
60
92
  allow(HTTPkit::Request).to receive(:new) { request }
61
- allow(client).to receive(:perform) { served }
93
+ allow(client).to receive(:perform) { served }
62
94
  end
63
95
 
64
96
  subject! { client.request(:head, '/wat') }
65
97
 
66
98
  specify do
67
99
  expect(HTTPkit::Request).to have_received(:new).with(:head, '/wat')
68
- expect(client).to have_received(:perform).with(request)
100
+ expect(client).to have_received(:perform).with(request)
69
101
 
70
102
  expect(subject).to be(response)
71
103
  end
72
104
  end
73
105
 
74
106
  describe '#perform' do
75
- let(:request) { double('request', add_extra_headers: nil) }
107
+ let(:request) { HTTPkit::Request.new(:get, '/') }
76
108
  let(:closed_reason) { nil }
77
109
 
78
110
  before do
@@ -80,29 +112,26 @@ describe HTTPkit::Client do
80
112
  allow(connection.closed).to receive(:reason) { closed_reason }
81
113
 
82
114
  @fibers = []
83
- allow(handler).to receive(:perform) { @fibers << Fiber.current }
115
+ allow(handler).to receive(:perform) { @fibers << Fiber.current }
84
116
  allow(connection).to receive(:serialize) { @fibers << Fiber.current }
85
117
  end
86
118
 
87
119
  subject! { client.perform(request) }
88
120
 
89
121
  it 'sends the request on the wire' do
90
- expect(handler).to have_received(:perform).with(request)
91
- expect(connection).to have_received(:serialize).with(request)
92
-
93
- expect(@fibers).not_to include(Fiber.current)
94
- expect(@fibers.uniq).to be_one
122
+ expect(handler).to have_received(:perform).with(kind_of(request.class))
123
+ expect(connection)
124
+ .to have_received(:serialize).with(kind_of(request.class))
95
125
 
96
- expect(request).to have_received(:add_extra_headers)
97
- .with('User-Agent' => "httpkit/#{HTTPkit::VERSION}",
98
- 'Host' => "#{config[:address]}:#{config[:port]}")
126
+ expect(@fibers).not_to include(Fiber.current)
127
+ expect(@fibers.uniq).to be_one
99
128
  end
100
129
 
101
130
  describe 'with closed connection' do
102
131
  let(:closed_reason) { double }
103
132
 
104
133
  it 'rejects the request' do
105
- expect(subject).to be_rejected
134
+ expect(subject).to be_rejected
106
135
  expect(subject.reason).to be(closed_reason)
107
136
  expect(connection).to_not have_received(:serialize)
108
137
  end
@@ -125,14 +154,22 @@ describe HTTPkit::Client do
125
154
  end
126
155
 
127
156
  it 'correlates response with request, and notifies handlers' do
128
- expect(served).to be_fulfilled
157
+ expect(served).to be_fulfilled
129
158
  expect(served.value).to be(response)
130
- expect(other_served).to be_fulfilled
159
+ expect(other_served).to be_fulfilled
131
160
  expect(other_served.value).to be(other_response)
132
161
 
133
- expect(handler).to have_received(:receive).with(request, response)
134
162
  expect(handler)
135
- .to have_received(:receive).with(other_request, other_response)
163
+ .to have_received(:receive).with(kind_of(request.class),
164
+ kind_of(response.class)).twice
165
+ end
166
+ end
167
+
168
+ describe 'without outstanding request' do
169
+ subject! { client.receive(response) }
170
+
171
+ it 'does not do anything' do
172
+ expect(handler).not_to have_received(:receive)
136
173
  end
137
174
  end
138
175
 
@@ -153,7 +190,7 @@ describe HTTPkit::Client do
153
190
  end
154
191
 
155
192
  it 'wires up #finish' do
156
- client.should have_received(:finish).with(request)
193
+ client.should have_received(:finish).with(kind_of(request.class))
157
194
  end
158
195
  end
159
196
 
@@ -182,8 +219,8 @@ describe HTTPkit::Client do
182
219
  end
183
220
 
184
221
  describe '#finish' do
185
- let(:request) { open_request }
186
- let(:other_request) { open_request }
222
+ let(:request) { open_request(:get) }
223
+ let(:other_request) { open_request(:head) }
187
224
  let(:response) { open_response }
188
225
 
189
226
  before do
@@ -197,16 +234,21 @@ describe HTTPkit::Client do
197
234
  end
198
235
 
199
236
  it 'removes the request' do
200
- expect(handler).to have_received(:receive).with(other_request, response)
237
+ expect(handler).to have_received(:receive) { |req, res|
238
+ expect(req.http_method).to be(:head)
239
+ expect(res).to be(res)
240
+ }
201
241
  end
202
242
 
203
243
  it 'notifies the handlers' do
204
- expect(handler).to have_received(:finish).with(request)
244
+ expect(handler).to have_received(:finish) { |req|
245
+ expect(req.http_method).to be(:get)
246
+ }
205
247
  end
206
248
  end
207
249
 
208
250
  describe '#teardown' do
209
- let(:requests) { [closed_request, closed_request] }
251
+ let(:requests) { [closed_request, closed_request, closed_request] }
210
252
  let(:responses) { [open_response] }
211
253
  let(:reason) { double('reason') }
212
254
 
@@ -216,15 +258,22 @@ describe HTTPkit::Client do
216
258
 
217
259
  before do
218
260
  client.receive(responses[0])
261
+ served[1].reject
219
262
  end
220
263
 
221
264
  subject! { client.teardown(reason) }
222
265
 
223
266
  it 'rejects outstanding requests and responses' do
224
- expect(responses[0].body.closed).to be_rejected
267
+ expect(responses[0].body.closed).to be_rejected
225
268
  expect(responses[0].body.closed.reason).to be(reason)
226
- expect(served[1]).to be_rejected
227
- expect(served[1].reason).to be(reason)
269
+ expect(served[2]).to be_rejected
270
+ expect(served[2].reason).to be(reason)
228
271
  end
229
272
  end
273
+
274
+ describe '#find_request'
275
+
276
+ describe '#perform!'
277
+
278
+ describe '#setup_connection'
230
279
  end
@@ -10,9 +10,9 @@ describe HTTPkit::Connection::EventMachine do
10
10
  let(:message) { open_request }
11
11
 
12
12
  before do
13
- allow(connection).to receive(:close_connection_after_writing)
14
- allow(HTTP::Parser).to receive(:new) { parser }
15
- allow(HTTPkit::Serializer).to receive(:new) { serializer }
13
+ allow(connection).to receive(:close_connection_after_writing)
14
+ allow(HTTP::Parser).to receive(:new) { parser }
15
+ allow(HTTPkit::Serializer).to receive(:new) { serializer }
16
16
  allow(HTTPkit::Support::Message).to receive(:build) { message }
17
17
 
18
18
  connection.instance_variable_set(:@signature, 123)
@@ -34,7 +34,7 @@ describe HTTPkit::Connection::EventMachine do
34
34
  subject! { described_class.start_client(config, client_class) }
35
35
 
36
36
  it 'starts a Client connection' do
37
- expect(EM).to have_received(:connect)
37
+ expect(EM).to have_received(:connect)
38
38
  .with(config[:address], config[:port], described_class)
39
39
  expect(client_class).to have_received(:new)
40
40
  .with(config, connection)
@@ -54,7 +54,7 @@ describe HTTPkit::Connection::EventMachine do
54
54
  subject! { described_class.start_server(config, server_class) }
55
55
 
56
56
  it 'starts a Client connection' do
57
- expect(EM).to have_received(:start_server)
57
+ expect(EM).to have_received(:start_server)
58
58
  .with(config[:address], config[:port], described_class, kind_of(Proc))
59
59
  expect(server_class).to have_received(:new)
60
60
  .with(config, connection)
@@ -90,8 +90,7 @@ describe HTTPkit::Connection::EventMachine do
90
90
 
91
91
  it 'feeds a serializer' do
92
92
  expect(HTTPkit::Serializer).to have_received(:new).with(message, writer)
93
- expect(serializer).to have_received(:setup_body)
94
- expect(serializer).to have_received(:serialize)
93
+ expect(serializer).to have_received(:serialize)
95
94
  end
96
95
  end
97
96
 
@@ -109,7 +108,7 @@ describe HTTPkit::Connection::EventMachine do
109
108
  subject! { connection.close(reason) }
110
109
 
111
110
  it 'rejects the promise' do
112
- expect(connection.closed).to be_rejected
111
+ expect(connection.closed).to be_rejected
113
112
  expect(connection.closed.reason).to be(reason)
114
113
  expect(connection).to have_received(:close_connection_after_writing)
115
114
  end
@@ -130,7 +129,7 @@ describe HTTPkit::Connection::EventMachine do
130
129
  let(:error) { RuntimeError.new }
131
130
 
132
131
  before do
133
- allow(parser).to receive(:<<) { raise error }
132
+ allow(parser).to receive(:<<) { raise error }
134
133
  allow(connection).to receive(:close)
135
134
  end
136
135
 
@@ -145,7 +144,7 @@ describe HTTPkit::Connection::EventMachine do
145
144
  subject! { connection.unbind }
146
145
 
147
146
  it 'fulfills the promise' do
148
- expect(connection.closed).to be_fulfilled
147
+ expect(connection.closed).to be_fulfilled
149
148
  expect(connection.closed.value).to be(nil)
150
149
  end
151
150
 
@@ -155,7 +154,7 @@ describe HTTPkit::Connection::EventMachine do
155
154
  subject! { connection.unbind(reason) }
156
155
 
157
156
  it 'rejects the promise' do
158
- expect(connection.closed).to be_rejected
157
+ expect(connection.closed).to be_rejected
159
158
  expect(connection.closed.reason).to be(reason)
160
159
  end
161
160
  end
@@ -170,7 +169,7 @@ describe HTTPkit::Connection::EventMachine do
170
169
 
171
170
  it 'builds the message and passes it on' do
172
171
  expect(HTTPkit::Support::Message).to have_received(:build).with(parser)
173
- expect(parse).to have_received(:call).with(message)
172
+ expect(parse).to have_received(:call).with(message)
174
173
  end
175
174
  end
176
175
 
@@ -192,7 +191,7 @@ describe HTTPkit::Connection::EventMachine do
192
191
 
193
192
  it 'passes chunk to message body' do
194
193
  expect(message.body.to_s).to eq(chunks.join)
195
- expect(progress).to eq(chunks)
194
+ expect(progress).to eq(chunks)
196
195
  end
197
196
  end
198
197
 
@@ -2,40 +2,81 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe HTTPkit, '#run', reactor: false do
6
- subject! do
7
- HTTPkit.run do
8
- @reactor = EM.reactor_running?
9
- @fiber = Fiber.current
5
+ describe HTTPkit do
6
+ describe '.run' do
7
+ subject! do
8
+ HTTPkit.run do
9
+ @reactor = EM.reactor_running?
10
+ @fiber = Fiber.current
11
+ end
10
12
  end
11
- end
12
13
 
13
- it 'starts an EventMachine reactor' do
14
- expect(@reactor).to be(true)
15
- end
14
+ it 'starts an EventMachine reactor' do
15
+ expect(@reactor).to be(true)
16
+ end
16
17
 
17
- it 'yields in a new Fiber' do
18
- expect(@fiber).not_to be(Fiber.current)
19
- end
18
+ it 'yields in a new Fiber' do
19
+ expect(@fiber).not_to be(Fiber.current)
20
+ end
20
21
 
21
- it 'stops the EventMachine reactor' do
22
- expect(EM.reactor_running?).to be(false)
22
+ it 'stops the EventMachine reactor' do
23
+ expect(EM.reactor_running?).to be(false)
24
+ end
23
25
  end
24
- end
25
26
 
26
- describe HTTPkit, '#stop', reactor: false do
27
- subject! do
28
- EM.run do
29
- EM.add_timer(1.0) { @timer = true }
30
- HTTPkit.stop
27
+ describe '.start' do
28
+ subject! do
29
+ HTTPkit.start do
30
+ @reactor = EM.reactor_running?
31
+ @fiber = Fiber.current
32
+ EM.stop
33
+ EM.next_tick {}
34
+ end
35
+ end
36
+
37
+ it 'starts an EventMachine reactor' do
38
+ expect(@reactor).to be(true)
39
+ end
40
+
41
+ it 'yields in a new Fiber' do
42
+ expect(@fiber).not_to be(Fiber.current)
31
43
  end
32
44
  end
33
45
 
34
- it 'stops the EventMachine reactor' do
35
- expect(EM.reactor_running?).to be(false)
46
+ describe '.stop' do
47
+ subject! do
48
+ EM.run do
49
+ EM.add_timer(1.0) { @timer = true }
50
+ HTTPkit.stop
51
+ end
52
+ end
53
+
54
+ it 'stops the EventMachine reactor' do
55
+ expect(EM.reactor_running?).to be(false)
56
+ end
57
+
58
+ it 'stops EventMachine timers' do
59
+ expect(@timer).not_to be(true)
60
+ end
36
61
  end
37
62
 
38
- it 'stops EventMachine timers' do
39
- expect(@timer).not_to be(true)
63
+ describe '.sleep', reactor: true do
64
+ subject { HTTPkit.sleep(0.005) }
65
+
66
+ let(:fiber) do
67
+ @slept = false
68
+ Fiber.new do
69
+ subject
70
+ @slept = true
71
+ end
72
+ end
73
+
74
+ it 'sleeps for the given number of seconds' do
75
+ fiber.resume
76
+ expect(@slept).to be(false)
77
+ sleep(0.005)
78
+ tick(3)
79
+ expect(@slept).to be(true)
80
+ end
40
81
  end
41
82
  end