hatetepe 0.4.1 → 0.5.0.pre

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,355 +1,125 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  require "spec_helper"
2
4
  require "hatetepe/server"
3
5
 
4
- describe Hatetepe::Server do
5
- let(:server) {
6
- Hatetepe::Server.allocate.tap {|s|
7
- s.send :initialize, config
8
- s.stub :comm_inactivity_timeout=
9
- s.post_init
10
- s.requests << request
11
- }
12
- }
13
- let(:request) { Hatetepe::Request.new :get, "/" }
14
- let(:env) { request.to_h }
15
-
16
- let(:app) { stub "app" }
17
- let(:host) { "127.0.4.1" }
18
- let(:port) { 8081 }
19
- let(:errors) { stub "errors", :<< => nil, :flush => nil }
20
- let(:config) {
21
- {
22
- :app => app,
23
- :host => host,
24
- :port => port,
25
- :errors => errors,
26
- :timeout => 0.0123
27
- }
28
- }
29
-
30
- before do
31
- server.stub :sockaddr => [42424, "127.0.42.1"]
32
- @old_env, ENV["RACK_ENV"] = ENV["RACK_ENV"], "testing"
33
- end
34
-
35
- after do
36
- ENV["RACK_ENV"] = @old_env
6
+ describe Hatetepe::Server, "(public API)" do
7
+ describe ".start(config, &app)" do
8
+ it "starts a server that listens on the supplied interface and port"
9
+ it "passes the config to incoming connections"
10
+ it "uses the passed block as app if any was passed"
37
11
  end
38
-
39
- it "inherits from Hatetepe::Connection" do
40
- server.should be_a(Hatetepe::Connection)
41
- end
42
-
43
- context ".start(config)" do
44
- it "starts an EventMachine server" do
45
- args = [host, port, Hatetepe::Server, config]
46
- EM.should_receive(:start_server).with(*args) { server }
47
-
48
- Hatetepe::Server.start(config).should equal(server)
49
- end
12
+
13
+ describe ".stop" do
14
+ it "waits for all requests to finish"
15
+ it "stops the server"
50
16
  end
51
-
52
- context "#initialize(config)" do
53
- let(:server) { Hatetepe::Server.allocate }
54
-
55
- it "sets up the error stream" do
56
- server.send :initialize, config
57
- server.errors.should equal(errors)
58
- server.config[:errors].should be_nil
59
- end
60
-
61
- it "uses stderr as default error stream" do
62
- config.delete :errors
63
- server.send :initialize, config
64
- server.errors.should equal($stderr)
65
- end
66
-
67
- it "assumes a default connection inactivity timeout of 1 seconds" do
68
- server.send :initialize, {}
69
- server.config[:timeout].should equal(1)
70
- end
17
+
18
+ describe ".stop!" do
19
+ it "immediately stops the server"
71
20
  end
72
-
73
- context "#post_init" do
74
- let :server do
75
- Hatetepe::Server.allocate.tap do |s|
76
- s.send :initialize, config
77
- s.stub :comm_inactivity_timeout=
21
+
22
+ describe "config[:app].call(env)" do
23
+ let :subject do
24
+ Object.new.tap do |s|
25
+ s.extend Hatetepe::Server
26
+ s.stub({
27
+ :config => {
28
+ :host => "127.0.5.1",
29
+ :port => 3000,
30
+ :app => stub("app")
31
+ },
32
+ :send_data => nil
33
+ })
34
+ s.stub(:comm_inactivity_timeout=)
35
+ s.post_init
78
36
  end
79
37
  end
80
-
81
- it "sets up the request queue" do
82
- server.post_init
83
- server.requests.should be_an(Array)
84
- server.requests.should be_empty
85
- end
86
-
87
- it "sets up the parser" do
88
- server.post_init
89
- server.parser.should respond_to(:<<)
90
- server.parser.on_request[0].should == server.requests.method(:<<)
91
- end
92
-
93
- it "sets up the builder" do
94
- server.post_init
95
- server.builder.on_write[0].should == server.method(:send_data)
96
- end
97
-
98
- it "builds the app" do
99
- server.post_init
100
- server.app.should be_a(Hatetepe::Server::Pipeline)
101
- server.app.app.should be_a(Hatetepe::Server::App)
102
- server.app.app.app.should be_a(Hatetepe::Server::KeepAlive)
103
- server.app.app.app.app.should be_a(Hatetepe::Server::Proxy)
104
- server.app.app.app.app.app.should equal(app)
105
- end
106
-
107
- it "starts the connection inactivity tracking" do
108
- server.should_receive(:comm_inactivity_timeout=).with 0.0123
109
- server.post_init
110
- end
111
-
112
- it "enables request processing" do
113
- server.post_init
114
- server.processing_enabled.should be_true
115
- end
116
- end
117
-
118
- context "#receive_data(data)" do
119
- before do
120
- ENV.delete "RACK_ENV"
121
- server.stub :close_connection
122
- end
123
-
124
- it "feeds data into the parser" do
125
- data = stub("data")
126
- server.parser.should_receive(:<<).with data
127
- server.receive_data data
128
- end
129
-
130
- it "closes the connection if parsing fails" do
131
- server.parser.should_receive(:<<).and_raise(Hatetepe::ParserError)
132
- server.should_receive :close_connection
133
-
134
- server.receive_data "irrelevant data"
135
- end
136
-
137
- it "re-raises parsing errors if RACK_ENV is testing" do
138
- ENV["RACK_ENV"] = "testing"
139
- server.parser.should_receive(:<<).and_raise Hatetepe::ParserError
140
-
141
- expect {
142
- server.receive_data "irrelevant data"
143
- }.to raise_error(Hatetepe::ParserError)
144
- end
145
-
146
- it "closes the connection when catching an exception" do
147
- server.parser.should_receive(:<<).and_raise Exception
148
- server.should_receive :close_connection_after_writing
149
-
150
- server.receive_data ""
151
- end
152
-
153
- it "re-raises caught exceptions" do
154
- ENV["RACK_ENV"] = "testing"
155
- server.parser.should_receive(:<<).and_raise Exception
156
-
157
- expect { server.receive_data "" }.to raise_error(Exception)
158
- end
159
-
160
- it "logs caught exceptions" do
161
- server.parser.should_receive(:<<).and_raise "error message"
162
- errors.should_receive(:<<) {|str|
163
- str.should include("error message")
164
- }
165
- errors.should_receive :flush
166
-
167
- server.receive_data ""
168
- end
169
- end
170
-
171
- context "#process" do
172
- before do
173
- request.stub :to_h => env
174
- app.stub :call => [-1]
175
- end
176
-
177
- it "puts useful stuff into env[]" do
178
- app.should_receive(:call) {|e|
179
- e.should equal(env)
180
- e["rack.url_scheme"].should == "http"
181
- e["hatetepe.connection"].should equal(server)
182
- e["rack.input"].source.should equal(server)
183
- e["rack.errors"].should equal(server.errors)
184
- e["rack.multithread"].should be_false
185
- e["rack.multiprocess"].should be_false
186
- e["rack.run_once"].should be_false
187
-
188
- e["SERVER_NAME"].should == host
189
- e["SERVER_NAME"].should_not equal(host)
190
- e["SERVER_PORT"].should == String(port)
191
- e["REMOTE_ADDR"].should == server.remote_address
192
- e["REMOTE_ADDR"].should_not equal(server.remote_address)
193
- e["REMOTE_PORT"].should == String(server.remote_port)
194
- e["HTTP_HOST"].should == "#{host}:#{port}"
195
-
196
- [-1]
197
- }
198
- server.process
199
- end
200
-
201
- it "calls the app within a new Fiber" do
202
- outer_fiber = Fiber.current
203
- app.should_receive(:call) {
204
- Fiber.current.should_not equal(outer_fiber)
205
- [-1]
206
- }
207
- server.process
208
- end
209
-
210
- it "is a no-op if processing is disabled" do
211
- server.processing_enabled = false
212
- app.should_not_receive :call
213
- server.process
214
- end
215
-
216
- let(:another_request) { Hatetepe::Request.new :get, "/asdf" }
217
-
218
- it "disables the connection timeout until the last request is finished" do
219
- server.requests << another_request
220
-
221
- server.should_receive(:comm_inactivity_timeout=).with 0
222
- server.process
223
-
224
- server.should_not_receive(:comm_inactivity_timeout=).with config[:timeout]
225
- server.requests.delete request
226
- request.succeed
227
-
228
- server.rspec_verify
229
- server.rspec_reset
230
-
231
- server.should_receive(:comm_inactivity_timeout=).with config[:timeout]
232
- server.requests.delete another_request
233
- another_request.succeed
234
- end
235
- end
236
-
237
- context "env[stream.start].call(response)" do
238
- let(:previous) { EM::DefaultDeferrable.new }
239
- let(:response) {
240
- [200, {"Key" => "value"}, Rack::STREAMING]
241
- }
242
-
243
- before {
244
- server.requests.unshift previous
245
- app.stub(:call) {|e| response }
246
- request.stub :succeed
247
- server.builder.stub :response_line
248
- server.builder.stub :headers
249
- }
250
-
251
- it "deletes itself from env[] to prevent multiple calls" do
252
- app.stub(:call) {|e|
253
- e["stream.start"].call response
254
- e.key?("stream.start").should be_false
255
- [-1]
256
- }
257
- previous.succeed
258
- server.process
259
- end
260
-
261
- # TODO this should be moved to a Server::Pipeline spec
262
- it "waits for the previous request's response to finish" do
263
- server.builder.should_not_receive :response
264
- server.process
265
- end
266
- end
267
-
268
- context "env[stream.send].call(chunk)" do
269
- it "passes data to the builder" do
270
- app.stub(:call) {|e|
271
- e["stream.send"].should == server.builder.method(:body_chunk)
272
- [-1]
273
- }
274
- server.process
275
- end
276
- end
277
-
278
- context "env[stream.close].call" do
279
- before {
280
- server.builder.stub :complete
281
- request.stub :succeed
282
- }
283
-
284
- it "leaves the connection open" do
285
- server.should_not_receive :close_connection
286
- app.stub(:call) {|e|
287
- server.requests << stub("another request")
288
- e["stream.close"].call
289
- [-1]
290
- }
291
- server.process
38
+
39
+ let :app do
40
+ subject.config[:app]
292
41
  end
293
-
294
- it "deletes itself and stream.send from env[] to prevent multiple calls" do
295
- app.stub(:call) {|e|
296
- e["stream.close"].call
297
- e.key?("stream.send").should be_false
298
- e.key?("stream.close").should be_false
299
- [-1]
300
- }
301
- server.process
42
+
43
+ let :http_request do
44
+ [
45
+ "POST /foo/bar?key=value HTTP/1.1",
46
+ "Host: themachine.local",
47
+ "Content-Length: 13",
48
+ "",
49
+ "Hello, world!"
50
+ ].join("\r\n")
302
51
  end
303
- end
304
-
305
- context "#start_response(response)" do
306
- let(:previous) { EM::DefaultDeferrable.new }
307
- let(:response) { [200, {"Key" => "value"}, Rack::STREAMING] }
308
-
309
- before {
310
- server.requests.unshift previous
311
- app.stub(:call) {|e| response }
312
- request.stub :succeed
313
- server.builder.stub :response_line
314
- server.builder.stub :headers
315
- }
316
-
317
- it "initiates the response" do
318
- server.builder.should_receive(:response_line) {|code|
319
- code.should equal(response[0])
320
- }
321
- server.builder.should_receive(:headers) {|headers|
322
- headers["Key"].should equal(response[1]["Key"])
323
- headers["Server"].should == "hatetepe/#{Hatetepe::VERSION}"
324
- }
325
- previous.succeed
326
- server.process
52
+
53
+ let :http_response do
54
+ [
55
+ "HTTP/1.1 403 Forbidden",
56
+ "Content-Type: text/plain",
57
+ "Transfer-Encoding: chunked",
58
+ "",
59
+ "b",
60
+ "Mmh, nöö.",
61
+ "0",
62
+ "",
63
+ ""
64
+ ].join("\r\n")
327
65
  end
328
- end
329
-
330
- context "#close_response(request)" do
331
- before do
332
- server.builder.stub :complete
333
- request.stub :succeed
334
- app.stub :call do |e|
335
- e["stream.close"].call
336
- [-1]
66
+
67
+ it "receives the Rack Env hash as parameter" do
68
+ app.should_receive :call do |env|
69
+ Rack::Lint.new(app).check_env(env)
70
+ env["REQUEST_METHOD"].should == "POST"
71
+ env["REQUEST_URI"].should == "/foo/bar?key=value"
72
+ env["HTTP_HOST"].should == "themachine.local"
73
+ env["rack.input"].read.should == "Hello, world!"
74
+ [ 200, {}, [] ]
337
75
  end
76
+
77
+ subject.receive_data(http_request)
338
78
  end
339
-
340
- it "removes the request from the request queue" do
341
- server.process
342
- server.requests.should be_empty
343
- end
344
-
345
- it "completes the response" do
346
- server.builder.should_receive :complete
347
- server.process
79
+
80
+ it "returns a response array that will be sent to the client" do
81
+ app.should_receive :call do |env|
82
+ [ 403, { "Content-Type" => "text/plain" }, [ "Mmh, nöö." ] ]
83
+ end
84
+
85
+ sent = ""
86
+ subject.stub(:send_data) {|data| sent << data }
87
+
88
+ subject.receive_data(http_request)
89
+ sent.should == http_response
348
90
  end
349
-
350
- it "succeeds the request" do
351
- request.should_receive :succeed
352
- server.process
91
+
92
+ it "returns asynchronously" do
93
+ app.should_receive :call do |env|
94
+ EM::Synchrony.add_timer 0.5 do
95
+ response = [ 403, { "Content-Type" => "text/plain" }, [ "Mmh, nöö." ] ]
96
+ env["async.callback"].call(response)
97
+ end
98
+ [ -1, {}, [] ]
99
+ end
100
+
101
+ sent = ""
102
+ subject.stub(:send_data) {|data| sent << data }
103
+
104
+ subject.receive_data(http_request)
105
+ EM::Synchrony.sleep(0.55)
106
+ sent.should == http_response
353
107
  end
354
108
  end
355
109
  end
110
+
111
+ describe Hatetepe::Server, "(EventMachine/sermipublic API)" do
112
+ describe "#initialize(config)"
113
+
114
+ describe "#post_init"
115
+
116
+ describe "#receive_data(data)"
117
+
118
+ describe "#unbind(reason)"
119
+ end
120
+
121
+ describe Hatetepe::Server, "(private API)" do
122
+ describe "#process_request(request)"
123
+
124
+ describe "#send_response(response)"
125
+ end
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hatetepe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
5
- prerelease:
4
+ version: 0.5.0.pre
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Lars Gierth
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-13 00:00:00.000000000 Z
12
+ date: 2012-04-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: http_parser.rb
16
- requirement: &69946770 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,21 +21,31 @@ dependencies:
21
21
  version: 0.5.3
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *69946770
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.5.3
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: eventmachine
27
- requirement: &69946160 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
- - - ! '>='
35
+ - - ~>
31
36
  - !ruby/object:Gem::Version
32
- version: '0'
37
+ version: 1.0.0.beta.4
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *69946160
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0.beta.4
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: em-synchrony
38
- requirement: &69945450 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
51
  - - ~>
@@ -43,10 +53,15 @@ dependencies:
43
53
  version: '1.0'
44
54
  type: :runtime
45
55
  prerelease: false
46
- version_requirements: *69945450
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
47
62
  - !ruby/object:Gem::Dependency
48
63
  name: rack
49
- requirement: &69944990 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
50
65
  none: false
51
66
  requirements:
52
67
  - - ! '>='
@@ -54,21 +69,15 @@ dependencies:
54
69
  version: '0'
55
70
  type: :runtime
56
71
  prerelease: false
57
- version_requirements: *69944990
58
- - !ruby/object:Gem::Dependency
59
- name: async-rack
60
- requirement: &69944610 !ruby/object:Gem::Requirement
72
+ version_requirements: !ruby/object:Gem::Requirement
61
73
  none: false
62
74
  requirements:
63
75
  - - ! '>='
64
76
  - !ruby/object:Gem::Version
65
77
  version: '0'
66
- type: :runtime
67
- prerelease: false
68
- version_requirements: *69944610
69
78
  - !ruby/object:Gem::Dependency
70
79
  name: thor
71
- requirement: &69883990 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
72
81
  none: false
73
82
  requirements:
74
83
  - - ! '>='
@@ -76,10 +85,15 @@ dependencies:
76
85
  version: '0'
77
86
  type: :runtime
78
87
  prerelease: false
79
- version_requirements: *69883990
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
80
94
  - !ruby/object:Gem::Dependency
81
95
  name: rspec
82
- requirement: &69883740 !ruby/object:Gem::Requirement
96
+ requirement: !ruby/object:Gem::Requirement
83
97
  none: false
84
98
  requirements:
85
99
  - - ! '>='
@@ -87,21 +101,15 @@ dependencies:
87
101
  version: '0'
88
102
  type: :development
89
103
  prerelease: false
90
- version_requirements: *69883740
91
- - !ruby/object:Gem::Dependency
92
- name: fakefs
93
- requirement: &69883520 !ruby/object:Gem::Requirement
104
+ version_requirements: !ruby/object:Gem::Requirement
94
105
  none: false
95
106
  requirements:
96
107
  - - ! '>='
97
108
  - !ruby/object:Gem::Version
98
109
  version: '0'
99
- type: :development
100
- prerelease: false
101
- version_requirements: *69883520
102
110
  - !ruby/object:Gem::Dependency
103
111
  name: yard
104
- requirement: &69883290 !ruby/object:Gem::Requirement
112
+ requirement: !ruby/object:Gem::Requirement
105
113
  none: false
106
114
  requirements:
107
115
  - - ! '>='
@@ -109,10 +117,15 @@ dependencies:
109
117
  version: '0'
110
118
  type: :development
111
119
  prerelease: false
112
- version_requirements: *69883290
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
113
126
  - !ruby/object:Gem::Dependency
114
127
  name: rdiscount
115
- requirement: &69883080 !ruby/object:Gem::Requirement
128
+ requirement: !ruby/object:Gem::Requirement
116
129
  none: false
117
130
  requirements:
118
131
  - - ! '>='
@@ -120,7 +133,12 @@ dependencies:
120
133
  version: '0'
121
134
  type: :development
122
135
  prerelease: false
123
- version_requirements: *69883080
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
124
142
  description:
125
143
  email:
126
144
  - lars.gierth@gmail.com
@@ -134,14 +152,13 @@ files:
134
152
  - README.md
135
153
  - Rakefile
136
154
  - bin/hatetepe
155
+ - examples/parallel_requests.rb
137
156
  - hatetepe.gemspec
138
157
  - lib/hatetepe.rb
139
158
  - lib/hatetepe/body.rb
140
159
  - lib/hatetepe/builder.rb
141
160
  - lib/hatetepe/cli.rb
142
161
  - lib/hatetepe/client.rb
143
- - lib/hatetepe/client/keep_alive.rb
144
- - lib/hatetepe/client/pipeline.rb
145
162
  - lib/hatetepe/connection.rb
146
163
  - lib/hatetepe/deferred_status_fix.rb
147
164
  - lib/hatetepe/events.rb
@@ -150,25 +167,23 @@ files:
150
167
  - lib/hatetepe/request.rb
151
168
  - lib/hatetepe/response.rb
152
169
  - lib/hatetepe/server.rb
153
- - lib/hatetepe/server/app.rb
154
170
  - lib/hatetepe/server/keep_alive.rb
155
171
  - lib/hatetepe/server/pipeline.rb
156
- - lib/hatetepe/server/proxy.rb
172
+ - lib/hatetepe/server/rack_app.rb
157
173
  - lib/hatetepe/version.rb
158
174
  - lib/rack/handler/hatetepe.rb
159
175
  - spec/integration/cli/start_spec.rb
160
176
  - spec/integration/client/keep_alive_spec.rb
177
+ - spec/integration/client/timeout_spec.rb
161
178
  - spec/integration/server/keep_alive_spec.rb
179
+ - spec/integration/server/timeout_spec.rb
162
180
  - spec/spec_helper.rb
163
- - spec/unit/app_spec.rb
164
181
  - spec/unit/body_spec.rb
165
182
  - spec/unit/builder_spec.rb
166
- - spec/unit/client/pipeline_spec.rb
167
183
  - spec/unit/client_spec.rb
168
184
  - spec/unit/connection_spec.rb
169
185
  - spec/unit/events_spec.rb
170
186
  - spec/unit/parser_spec.rb
171
- - spec/unit/proxy_spec.rb
172
187
  - spec/unit/rack_handler_spec.rb
173
188
  - spec/unit/server_spec.rb
174
189
  homepage: https://github.com/lgierth/hatetepe
@@ -186,12 +201,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
186
201
  required_rubygems_version: !ruby/object:Gem::Requirement
187
202
  none: false
188
203
  requirements:
189
- - - ! '>='
204
+ - - ! '>'
190
205
  - !ruby/object:Gem::Version
191
- version: '0'
206
+ version: 1.3.1
192
207
  requirements: []
193
208
  rubyforge_project:
194
- rubygems_version: 1.8.12
209
+ rubygems_version: 1.8.21
195
210
  signing_key:
196
211
  specification_version: 3
197
212
  summary: The HTTP toolkit