hatetepe 0.5.2 → 0.6.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/.gitignore +7 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +4 -0
  4. data/.yardopts +1 -0
  5. data/Gemfile +9 -4
  6. data/Gemfile.devtools +55 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +39 -192
  9. data/Rakefile +3 -2
  10. data/bin/hatetepe +35 -2
  11. data/config/devtools.yml +2 -0
  12. data/config/flay.yml +3 -0
  13. data/config/flog.yml +2 -0
  14. data/config/mutant.yml +3 -0
  15. data/config/reek.yml +103 -0
  16. data/config/rubocop.yml +58 -0
  17. data/config/yardstick.yml +2 -0
  18. data/hatetepe.gemspec +23 -27
  19. data/lib/hatetepe/client/keep_alive.rb +59 -0
  20. data/lib/hatetepe/client/timeouts.rb +19 -0
  21. data/lib/hatetepe/client.rb +54 -302
  22. data/lib/hatetepe/connection/eventmachine.rb +61 -0
  23. data/lib/hatetepe/connection/status.rb +28 -0
  24. data/lib/hatetepe/errors.rb +7 -0
  25. data/lib/hatetepe/promise.rb +86 -0
  26. data/lib/hatetepe/request.rb +15 -39
  27. data/lib/hatetepe/response.rb +82 -22
  28. data/lib/hatetepe/serializer/encoding.rb +58 -0
  29. data/lib/hatetepe/serializer.rb +61 -0
  30. data/lib/hatetepe/server/keep_alive.rb +53 -13
  31. data/lib/hatetepe/server/timeouts.rb +17 -0
  32. data/lib/hatetepe/server.rb +37 -85
  33. data/lib/hatetepe/support/handlers.rb +19 -0
  34. data/lib/hatetepe/support/keep_alive.rb +14 -0
  35. data/lib/hatetepe/support/message.rb +40 -0
  36. data/lib/hatetepe/version.rb +3 -1
  37. data/lib/hatetepe.rb +29 -7
  38. data/spec/integration/error_handling_spec.rb +7 -0
  39. data/spec/integration/keep_alive_spec.rb +106 -0
  40. data/spec/integration/smoke_spec.rb +21 -0
  41. data/spec/integration/streaming_spec.rb +61 -0
  42. data/spec/integration/timeouts_spec.rb +82 -0
  43. data/spec/shared/integration/server_client_pair.rb +26 -0
  44. data/spec/spec_helper.rb +41 -10
  45. data/spec/support/handler.rb +55 -0
  46. data/spec/support/helper.rb +74 -0
  47. data/spec/unit/client_spec.rb +115 -156
  48. data/spec/unit/connection/eventmachine_spec.rb +146 -0
  49. data/spec/unit/request_spec.rb +35 -0
  50. data/spec/unit/response_spec.rb +42 -0
  51. data/spec/unit/server_spec.rb +65 -100
  52. data/spec/unit/support/keep_alive_spec.rb +52 -0
  53. data/spec/unit/support/message_spec.rb +41 -0
  54. metadata +68 -103
  55. data/Gemfile.lock +0 -46
  56. data/LICENSE +0 -19
  57. data/Procfile +0 -1
  58. data/config.ru +0 -7
  59. data/examples/parallel_requests.rb +0 -32
  60. data/lib/hatetepe/body.rb +0 -182
  61. data/lib/hatetepe/builder.rb +0 -171
  62. data/lib/hatetepe/cli.rb +0 -61
  63. data/lib/hatetepe/connection.rb +0 -73
  64. data/lib/hatetepe/events.rb +0 -35
  65. data/lib/hatetepe/message.rb +0 -13
  66. data/lib/hatetepe/parser.rb +0 -83
  67. data/lib/hatetepe/server/pipeline.rb +0 -20
  68. data/lib/hatetepe/server/rack_app.rb +0 -39
  69. data/lib/rack/handler/hatetepe.rb +0 -33
  70. data/spec/integration/cli/start_spec.rb +0 -113
  71. data/spec/integration/client/keep_alive_spec.rb +0 -23
  72. data/spec/integration/client/timeout_spec.rb +0 -97
  73. data/spec/integration/server/keep_alive_spec.rb +0 -27
  74. data/spec/integration/server/timeout_spec.rb +0 -51
  75. data/spec/unit/body_spec.rb +0 -205
  76. data/spec/unit/builder_spec.rb +0 -372
  77. data/spec/unit/connection_spec.rb +0 -62
  78. data/spec/unit/events_spec.rb +0 -96
  79. data/spec/unit/parser_spec.rb +0 -209
  80. data/spec/unit/rack_handler_spec.rb +0 -60
@@ -1,372 +0,0 @@
1
- require "spec_helper"
2
- require "hatetepe/builder"
3
-
4
- describe Hatetepe::Builder do
5
- let(:builder) { Hatetepe::Builder.allocate }
6
-
7
- describe ".build {|builder| ... }"
8
-
9
- describe "#initialize" do
10
- it "resets the builder" do
11
- builder.should_receive :reset
12
- builder.send :initialize
13
- end
14
-
15
- it "initializes the on_complete, on_write, on_error hooks" do
16
- builder.send :initialize
17
- [:complete, :write, :error].each do |hook|
18
- builder.send(:"on_#{hook}").tap do |h|
19
- h.should be_an(Array)
20
- h.should be_empty
21
- end
22
- end
23
- end
24
- end
25
-
26
- describe "#initialize {|builder| ... }" do
27
- it "yields the builder" do
28
- arg = nil
29
- builder.send(:initialize) {|b| arg = b }
30
- arg.should equal(builder)
31
- end
32
- end
33
-
34
- [:complete, :write, :error].each do |hook|
35
- describe "#on_#{hook} {|*| ... }" do
36
- let(:block) { proc {} }
37
- before { builder.send :initialize }
38
-
39
- it "adds a hook block" do
40
- builder.send :"on_#{hook}", &block
41
- builder.send(:"on_#{hook}").should include(block)
42
- end
43
- end
44
- end
45
-
46
- describe "#writing_trailing_headers?" do
47
- it "returns true if the builder state is :ready" do
48
- builder.stub :state => :ready
49
- builder.ready?.should be_true
50
- end
51
-
52
- it "returns false otherwise" do
53
- builder.stub :state => :something
54
- builder.ready?.should be_false
55
- end
56
- end
57
-
58
- describe "#reset" do
59
- before { builder.send :reset }
60
-
61
- # XXX maybe don't test chunked flag
62
- it "resets the chunked flag and the builder state" do
63
- builder.chunked?.should be_nil
64
- builder.ready?.should be_true
65
- end
66
- end
67
-
68
- # XXX maybe test states and flags where they are being mutated
69
- describe "#ready?"
70
- describe "#writing_headers?"
71
- describe "#writing_body?"
72
- describe "#writing_trailing_headers?"
73
- describe "#chunked?"
74
-
75
- describe "#request(array)" do
76
- let(:req) { [:get, "/foo", {"Key" => "value"}, double("body")] }
77
-
78
- before { builder.send :initialize }
79
-
80
- it "is a shortcut for #request_line, #headers, #body, #complete" do
81
- builder.should_receive(:request_line).with req[0], req[1], "1.1"
82
- builder.should_receive(:headers).with req[2]
83
- builder.should_receive(:body).with req[3]
84
- builder.should_receive :complete
85
- builder.request req
86
- end
87
-
88
- it "doesn't require a body (fourth element)" do
89
- builder.should_receive(:request_line).with req[0], req[1], "1.1"
90
- builder.should_receive(:headers).with req[2]
91
- builder.should_not_receive :body
92
- builder.request req[0..2]
93
- end
94
- end
95
-
96
- describe "#request_line(verb, uri, version)" do
97
- before { builder.send :initialize }
98
-
99
- it "writes a request line" do
100
- builder.should_receive(:write).with "GET /foo HTTP/1.0\r\n"
101
- builder.request_line :get, "/foo", "1.0"
102
- end
103
-
104
- it "changes the state to :writing_headers" do
105
- builder.request_line :get, "/foo"
106
- builder.state.should equal(:writing_headers)
107
- end
108
-
109
- it "defaults the version to 1.1" do
110
- builder.should_receive(:write).with "GET /foo HTTP/1.1\r\n"
111
- builder.request_line :get, "/foo"
112
- end
113
- end
114
-
115
- describe "#response_line(code, version)" do
116
- before { builder.send :initialize }
117
-
118
- it "writes a response line" do
119
- builder.should_receive(:write).with "HTTP/1.0 403 Forbidden\r\n"
120
- builder.response_line 403, "1.0"
121
- end
122
-
123
- it "changes the state to :writing_headers" do
124
- builder.response_line 403
125
- builder.state.should equal(:writing_headers)
126
- end
127
-
128
- it "default the version to 1.1" do
129
- builder.should_receive(:write).with "HTTP/1.1 403 Forbidden\r\n"
130
- builder.response_line 403
131
- end
132
-
133
- it "fails if there's no status message for code" do
134
- builder.should_receive :error
135
- builder.response_line 666
136
- end
137
- end
138
-
139
- describe "#response(array)" do
140
- let(:res) { [201, {"Key" => "value"}, double("body")] }
141
-
142
- before { builder.send :initialize }
143
-
144
- it "is a shortcut for #response_line, #headers, #body, #complete" do
145
- builder.should_receive(:response_line).with res[0], "1.1"
146
- builder.should_receive(:headers).with res[1]
147
- builder.should_receive(:body).with res[2]
148
- builder.should_receive :complete
149
- builder.response res
150
- end
151
-
152
- it "doesn't require a body (third element)" do
153
- builder.should_receive(:response_line).with res[0], "1.1"
154
- builder.should_receive(:headers).with res[1]
155
- builder.should_not_receive :body
156
- builder.response res[0..1]
157
- end
158
- end
159
-
160
- describe "#headers(hash)" do
161
- it "writes each of the header pairs" do
162
- builder.should_receive(:header).with "Key", "value"
163
- builder.should_receive(:header).with "Key2", "value2"
164
- builder.headers "Key" => "value", "Key2" => "value2"
165
- end
166
- end
167
-
168
- describe "#header(name, value)" do
169
- it "writes the header pair" do
170
- builder.should_receive(:raw_header).with "Key: value"
171
- builder.header "Key", "value"
172
- end
173
- end
174
-
175
- describe "#raw_header(header)" do
176
- before do
177
- builder.send :initialize
178
- builder.response_line 200
179
- end
180
-
181
- it "writes the header line" do
182
- builder.should_receive(:write).with "Key: value\r\n"
183
- builder.raw_header "Key: value"
184
- end
185
-
186
- it "fails if no request or response line has been written" do
187
- builder.reset
188
- builder.should_receive :error
189
- builder.raw_header "Key: value"
190
- end
191
-
192
- it "fails if body already started" do
193
- builder.header "Content-Length", 5
194
- builder.body_chunk "asd"
195
-
196
- builder.should_receive :error
197
- builder.raw_header "Key: value"
198
- end
199
-
200
- it "writes trailing header if body already started and transfer is chunked" do
201
- builder.header "Transfer-Encoding", "chunked"
202
- builder.body_chunk "asd"
203
-
204
- builder.should_not_receive :error
205
- builder.should_receive(:write).with "0\r\n"
206
- builder.should_receive(:write).with "Key: value\r\n"
207
- builder.raw_header "Key: value"
208
-
209
- builder.state.should equal(:writing_trailing_headers)
210
- end
211
-
212
- it "sets the chunked flag" do
213
- builder.header "Transfer-Encoding", "chunked"
214
- builder.chunked?.should be_true
215
-
216
- builder.reset
217
- builder.response_line 200
218
-
219
- builder.header "Content-Length", "0"
220
- builder.chunked?.should be_false
221
- end
222
-
223
- it "doesn't set the chunked flag a second time" do
224
- builder.header "Transfer-Encoding", "chunked"
225
- builder.chunked?.should be_true
226
-
227
- builder.header "Content-Length", "0"
228
- builder.chunked?.should be_true
229
- end
230
- end
231
-
232
- describe "#body(#each)" do
233
- let(:body) { [double("chunk#1"), double("chunk#2")] }
234
-
235
- it "calls #body_chunk for each element" do
236
- builder.should_receive(:body_chunk).with body[0]
237
- builder.should_receive(:body_chunk).with body[1]
238
- builder.body body
239
- end
240
- end
241
-
242
- describe "#body_chunk(chunk)" do
243
- before do
244
- builder.send :initialize
245
- builder.response_line 200
246
- end
247
-
248
- it "fails if no request or response line has been written" do
249
- builder.reset
250
- builder.should_receive :error
251
- builder.body_chunk "asd"
252
- end
253
-
254
- it "fails if already writing trailing headers" do
255
- builder.body_chunk "asd"
256
- builder.header "Key", "value"
257
- builder.should_receive :error
258
- builder.body_chunk "asd"
259
- end
260
-
261
- it "assumes Transfer-Encoding: chunked if chunked flag isn't set" do
262
- builder.should_receive(:header).with "Transfer-Encoding", "chunked"
263
- builder.body_chunk "asd"
264
- end
265
-
266
- it "changes the state to :writing_body" do
267
- builder.body_chunk "asd"
268
- builder.state.should equal(:writing_body)
269
- end
270
-
271
- it "writes chunked body data" do
272
- builder.body_chunk ""
273
- builder.should_receive(:write).with "c\r\nasdfoobarbaz\r\n"
274
- builder.body_chunk "asdfoobarbaz"
275
- end
276
-
277
- it "writes empty chunked data" do
278
- builder.body_chunk ""
279
- builder.should_receive(:write).with "0\r\n\r\n"
280
- builder.body_chunk ""
281
- end
282
-
283
- it "writes plain body data" do
284
- builder.header "Content-Length", "12"
285
- builder.body_chunk ""
286
- builder.should_receive(:write).with "asdfoobarbaz"
287
- builder.body_chunk "asdfoobarbaz"
288
- end
289
-
290
- it "doesn't write empty plain data" do
291
- builder.header "Content-Length", "123"
292
- builder.body_chunk ""
293
- builder.should_not_receive :write
294
- builder.body_chunk ""
295
- end
296
- end
297
-
298
- describe "#complete" do
299
- before do
300
- builder.send :initialize
301
- builder.response_line 200
302
- builder.stub :body_chunk
303
- end
304
-
305
- it "does nothing if state is :ready" do
306
- builder.reset
307
- builder.should_not_receive :write
308
- builder.complete
309
- end
310
-
311
- it "sets Content-Length to 0 if no body has been sent and transfer is chunked" do
312
- builder.should_receive(:header).with "Content-Length", "0"
313
- builder.complete
314
- end
315
-
316
- it "writes an empty body chunk" do
317
- builder.should_receive(:body_chunk).with ""
318
- builder.complete
319
- end
320
-
321
- let(:hook) { double "hook", :call => nil }
322
-
323
- it "calls the on_complete hooks" do
324
- builder.on_complete << hook
325
- hook.should_receive :call
326
- builder.complete
327
- end
328
-
329
- it "calls #reset" do
330
- builder.should_receive :reset
331
- builder.complete
332
- end
333
- end
334
-
335
- describe "#write(data)" do
336
- let(:hook) { double "hook" }
337
- let(:data) { double "data" }
338
-
339
- before { builder.send :initialize }
340
-
341
- it "calls the on_write hooks" do
342
- builder.on_write << hook
343
- hook.should_receive(:call).with data
344
- builder.write data
345
- end
346
- end
347
-
348
- describe "#error(message)" do
349
- let(:hook1) { double "hook#1" }
350
- let(:hook2) { double "hook#2" }
351
- let(:message) { "error! error!" }
352
- let(:exception) { double "exception" }
353
-
354
- before do
355
- builder.send :initialize
356
- builder.on_error << hook1 << hook2
357
- end
358
-
359
- it "calls the error hooks" do
360
- Hatetepe::BuilderError.stub :new => exception
361
-
362
- hook1.should_receive(:call).with exception
363
- hook2.should_receive(:call).with exception
364
- builder.error message
365
- end
366
-
367
- it "raises the exception if no hooks were added" do
368
- builder.on_error.clear
369
- proc { builder.error message }.should raise_error(Hatetepe::BuilderError, message)
370
- end
371
- end
372
- end
@@ -1,62 +0,0 @@
1
- require "spec_helper"
2
- require "hatetepe/connection"
3
-
4
- describe Hatetepe::Connection do
5
- let :conn do
6
- Object.new.extend Hatetepe::Connection
7
- end
8
-
9
- let(:address) { "127.0.0.1" }
10
- let(:port) { 34450 }
11
- let(:peername) { Socket.pack_sockaddr_in(port, address) }
12
-
13
- before { conn.stub :get_peername => peername }
14
-
15
- describe "#remote_address" do
16
- it "returns the remote peer's address" do
17
- conn.remote_address.should == address
18
- end
19
- end
20
-
21
- describe "#remote_port" do
22
- it "returns the remote peer's port" do
23
- conn.remote_port.should == port
24
- end
25
- end
26
-
27
- describe "#close_connection" do
28
- before { EM::Connection.any_instance.stub :close_connection }
29
-
30
- it "sets the closed-by-self flag" do
31
- pending "How to test a call to super?"
32
-
33
- conn.close_connection
34
- conn.should be_closed
35
- conn.should be_closed_by_self
36
- end
37
-
38
- let(:arg) { stub "arg" }
39
-
40
- it "calls EM::Connection.close_connection" do
41
- pending "How to test a call to super?"
42
-
43
- EM::Connection.any_instance.should_receive(:close_connection).with arg
44
- conn.close_connection arg
45
- end
46
- end
47
-
48
- describe "#unbind" do
49
- it "sets the closed-by-remote flag" do
50
- conn.unbind(nil)
51
- conn.should be_closed
52
- conn.should be_closed_by_remote
53
- end
54
-
55
- it "doesn't overwrite an existing closed-by flag" do
56
- conn.stub :closed? => true
57
- conn.unbind(nil)
58
- conn.should be_closed
59
- conn.should_not be_closed_by_remote
60
- end
61
- end
62
- end
@@ -1,96 +0,0 @@
1
- require "spec_helper"
2
- require "hatetepe/events"
3
-
4
- describe Hatetepe::Events do
5
- let(:klass) {
6
- Class.new {
7
- include Hatetepe::Events
8
- event :foo
9
- }
10
- }
11
- let(:obj) { klass.new }
12
-
13
- context "#event(name, *args)" do
14
- let(:args) { ["arg#1", "arg#2", "arg#3"] }
15
- let(:called) { [] }
16
-
17
- before {
18
- obj.on_foo {|*args| called << [:bar, args] }
19
- obj.on_foo {|*args| called << [:baz, args] }
20
- }
21
-
22
- it "calls the listeners" do
23
- obj.event :foo, *args
24
- called.should == [[:bar, args], [:baz, args]]
25
- end
26
- end
27
-
28
- context "#event!(name, *args)" do
29
- let(:args) { [:foo, "arg#1", "arg#2"] }
30
-
31
- it "forwards to #event" do
32
- obj.should_receive(:event).with(*args)
33
- obj.event! *args
34
- end
35
-
36
- it "changes the state to specified name" do
37
- obj.on_foo {
38
- obj.foo?.should be_true
39
- }
40
- obj.event! :foo
41
- end
42
- end
43
-
44
- context ".event(name, *more_names)" do
45
- before { klass.event :bar, :baz }
46
-
47
- it "adds #on_name method" do
48
- obj.should respond_to(:on_bar)
49
- end
50
-
51
- it "adds #name? method" do
52
- obj.should respond_to(:bar?)
53
- end
54
-
55
- it "calls itself for each additional name" do
56
- obj.should respond_to(:on_baz)
57
- obj.should respond_to(:baz?)
58
- end
59
- end
60
-
61
- context "#on_name {|*args| ... }" do
62
- let(:block) { proc {} }
63
-
64
- it "adds the block to the listener stack" do
65
- obj.on_foo &block
66
- obj.on_foo.should include(block)
67
- end
68
- end
69
-
70
- context "#on_name" do
71
- let(:blocks) { [proc {}, proc {}] }
72
-
73
- it "returns the listener stack" do
74
- obj.on_foo &blocks[0]
75
- obj.on_foo &blocks[1]
76
-
77
- obj.on_foo.should == blocks
78
- end
79
-
80
- it "returns an empty stack if no listeners have been added yet" do
81
- obj.on_foo.should be_empty
82
- end
83
- end
84
-
85
- context "#name?" do
86
- it "returns true if the state equals :name" do
87
- obj.stub :state => :foo
88
- obj.foo?.should be_true
89
- end
90
-
91
- it "returns false if the state doesn't equal :name" do
92
- obj.stub :state => :bar
93
- obj.foo?.should be_false
94
- end
95
- end
96
- end