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

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 (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