screw-unit 0.3.1
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.
- data/CHANGES +11 -0
- data/README.markdown +354 -0
- data/Rakefile +40 -0
- data/bin/screw_unit +6 -0
- data/bin/screw_unit_server +10 -0
- data/core/EXAMPLE.html +68 -0
- data/core/LICENSE +22 -0
- data/core/README.markdown +307 -0
- data/core/example/models/cat.js +5 -0
- data/core/example/models/man.js +17 -0
- data/core/example/spec/matchers/have.js +8 -0
- data/core/example/spec/models/cat_spec.js +31 -0
- data/core/example/spec/models/man_spec.js +34 -0
- data/core/example/spec/spec_helper.js +5 -0
- data/core/example/spec/suite.html +25 -0
- data/core/lib/jquery-1.2.6.js +3549 -0
- data/core/lib/jquery.fn.js +29 -0
- data/core/lib/jquery.print.js +109 -0
- data/core/lib/screw.assets.js +36 -0
- data/core/lib/screw.behaviors.js +91 -0
- data/core/lib/screw.builder.js +80 -0
- data/core/lib/screw.css +90 -0
- data/core/lib/screw.events.js +44 -0
- data/core/lib/screw.matchers.js +145 -0
- data/core/lib/screw.server.js +21 -0
- data/core/spec/behaviors_spec.js +178 -0
- data/core/spec/matchers_spec.js +237 -0
- data/core/spec/print_spec.js +152 -0
- data/core/spec/spec_helper.js +0 -0
- data/core/spec/suite.html +18 -0
- data/init.rb +0 -0
- data/lib/screw_unit.rb +26 -0
- data/lib/screw_unit/resources.rb +2 -0
- data/lib/screw_unit/resources/spec.rb +38 -0
- data/spec/functional/functional_spec.rb +25 -0
- data/spec/functional/functional_spec_helper.rb +55 -0
- data/spec/functional_suite.rb +10 -0
- data/spec/spec_suite.rb +3 -0
- data/spec/unit/js_test_core/specs/spec_dir_spec.rb +39 -0
- data/spec/unit/js_test_core/specs/spec_file_spec.rb +35 -0
- data/spec/unit/unit_spec_helper.rb +120 -0
- data/spec/unit_suite.rb +10 -0
- data/vendor/js-test-core/CHANGES +15 -0
- data/vendor/js-test-core/README +12 -0
- data/vendor/js-test-core/Rakefile +72 -0
- data/vendor/js-test-core/lib/js_test_core.rb +38 -0
- data/vendor/js-test-core/lib/js_test_core/client.rb +114 -0
- data/vendor/js-test-core/lib/js_test_core/extensions.rb +3 -0
- data/vendor/js-test-core/lib/js_test_core/extensions/time.rb +6 -0
- data/vendor/js-test-core/lib/js_test_core/rack.rb +2 -0
- data/vendor/js-test-core/lib/js_test_core/rack/commonlogger.rb +5 -0
- data/vendor/js-test-core/lib/js_test_core/rails_server.rb +22 -0
- data/vendor/js-test-core/lib/js_test_core/resources.rb +10 -0
- data/vendor/js-test-core/lib/js_test_core/resources/dir.rb +67 -0
- data/vendor/js-test-core/lib/js_test_core/resources/file.rb +49 -0
- data/vendor/js-test-core/lib/js_test_core/resources/file_not_found.rb +11 -0
- data/vendor/js-test-core/lib/js_test_core/resources/runner.rb +105 -0
- data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_dir.rb +46 -0
- data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_file.rb +17 -0
- data/vendor/js-test-core/lib/js_test_core/resources/suite.rb +40 -0
- data/vendor/js-test-core/lib/js_test_core/resources/suite_finish.rb +17 -0
- data/vendor/js-test-core/lib/js_test_core/resources/web_root.rb +63 -0
- data/vendor/js-test-core/lib/js_test_core/selenium.rb +2 -0
- data/vendor/js-test-core/lib/js_test_core/selenium/selenium_driver.rb +5 -0
- data/vendor/js-test-core/lib/js_test_core/selenium_server_configuration.rb +48 -0
- data/vendor/js-test-core/lib/js_test_core/server.rb +50 -0
- data/vendor/js-test-core/lib/js_test_core/thin.rb +3 -0
- data/vendor/js-test-core/lib/js_test_core/thin/backends/js_test_core_server.rb +9 -0
- data/vendor/js-test-core/lib/js_test_core/thin/js_test_core_connection.rb +8 -0
- data/vendor/js-test-core/spec/example_core/JsTestCore.css +0 -0
- data/vendor/js-test-core/spec/example_core/JsTestCore.js +0 -0
- data/vendor/js-test-core/spec/example_public/favicon.ico +0 -0
- data/vendor/js-test-core/spec/example_public/javascripts/foo.js +3 -0
- data/vendor/js-test-core/spec/example_public/javascripts/large_file.js +59 -0
- data/vendor/js-test-core/spec/example_public/javascripts/subdir/bar.js +1 -0
- data/vendor/js-test-core/spec/example_public/robots.txt +0 -0
- data/vendor/js-test-core/spec/example_public/stylesheets/example.css +3 -0
- data/vendor/js-test-core/spec/example_specs/failing_spec.js +5 -0
- data/vendor/js-test-core/spec/example_specs/foo/failing_spec.js +6 -0
- data/vendor/js-test-core/spec/example_specs/foo/passing_spec.js +6 -0
- data/vendor/js-test-core/spec/spec_suite.rb +2 -0
- data/vendor/js-test-core/spec/specs/failing_spec.js +0 -0
- data/vendor/js-test-core/spec/unit/js_test_core/client_spec.rb +166 -0
- data/vendor/js-test-core/spec/unit/js_test_core/rails_server_spec.rb +45 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/dir_spec.rb +52 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/file_not_found_spec.rb +16 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/file_spec.rb +128 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/runners/runner_spec.rb +283 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_dir_spec.rb +105 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_file_spec.rb +42 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/suite_finish_spec.rb +82 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/suite_spec.rb +86 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/web_root_spec.rb +32 -0
- data/vendor/js-test-core/spec/unit/js_test_core/selenium_server_configuration_spec.rb +49 -0
- data/vendor/js-test-core/spec/unit/js_test_core/server_spec.rb +117 -0
- data/vendor/js-test-core/spec/unit/thin/js_test_core_connection_spec.rb +6 -0
- data/vendor/js-test-core/spec/unit/unit_spec_helper.rb +134 -0
- data/vendor/js-test-core/spec/unit_suite.rb +10 -0
- data/vendor/js-test-core/vendor/thin-rest/CHANGES +2 -0
- data/vendor/js-test-core/vendor/thin-rest/README +0 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest.rb +9 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/connection.rb +116 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/extensions.rb +3 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/extensions/object.rb +21 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resource.rb +104 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resource_invalid.rb +4 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/routing_error.rb +5 -0
- data/vendor/js-test-core/vendor/thin-rest/spec/spec_suite.rb +5 -0
- data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/connection_spec.rb +207 -0
- data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/resource_spec.rb +127 -0
- data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest_spec_helper.rb +124 -0
- metadata +210 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
require "rubygems"
|
|
2
|
+
require "thin"
|
|
3
|
+
|
|
4
|
+
dir = File.dirname(__FILE__)
|
|
5
|
+
require "#{dir}/thin_rest/connection"
|
|
6
|
+
require "#{dir}/thin_rest/resource"
|
|
7
|
+
require "#{dir}/thin_rest/resource_invalid"
|
|
8
|
+
require "#{dir}/thin_rest/routing_error"
|
|
9
|
+
require "#{dir}/thin_rest/extensions"
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
module ThinRest
|
|
2
|
+
class Connection < Thin::Connection
|
|
3
|
+
attr_reader :resource, :rack_request
|
|
4
|
+
|
|
5
|
+
def process
|
|
6
|
+
guard_against_errors do
|
|
7
|
+
method = rack_request.request_method.downcase.to_sym
|
|
8
|
+
@resource = get_resource
|
|
9
|
+
resource.send(method)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def rack_request
|
|
14
|
+
@rack_request ||= Rack::Request.new(@request.env)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def send_head(status=200, additional_parameters={})
|
|
18
|
+
send_data(head(status, additional_parameters))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def head(status, additional_parameters)
|
|
22
|
+
parameters = {}
|
|
23
|
+
parameters['Connection'] = "close" unless request.persistent?
|
|
24
|
+
parameters.merge!(additional_parameters)
|
|
25
|
+
head_output = parameters.inject("HTTP/1.1 #{status} OK\r\nServer: Thin Rest Server\r\n") do |header, parameter|
|
|
26
|
+
header << "#{parameter[0]}: #{parameter[1]}\r\n"
|
|
27
|
+
end
|
|
28
|
+
if additional_parameters[:'Content-Length'] || additional_parameters['Content-Length']
|
|
29
|
+
head_output << "\r\n"
|
|
30
|
+
end
|
|
31
|
+
head_output
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def send_body(data)
|
|
35
|
+
terminate_after_sending do
|
|
36
|
+
send_data("Content-Length: #{data.length}\r\n\r\n")
|
|
37
|
+
send_data(data)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def terminate_after_sending
|
|
42
|
+
yield
|
|
43
|
+
unless request.persistent?
|
|
44
|
+
close_connection_after_writing
|
|
45
|
+
end
|
|
46
|
+
ensure
|
|
47
|
+
terminate_request
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def unbind
|
|
51
|
+
super
|
|
52
|
+
resource.unbind if resource
|
|
53
|
+
rescue Exception => e
|
|
54
|
+
handle_error e
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def terminate_request
|
|
58
|
+
persistent = persistent?
|
|
59
|
+
@resource = nil
|
|
60
|
+
@rack_request = nil
|
|
61
|
+
@request.close rescue nil
|
|
62
|
+
@response.close rescue nil
|
|
63
|
+
|
|
64
|
+
# Prepare the connection for another request if the client
|
|
65
|
+
# supports HTTP pipelining (persistent connection).
|
|
66
|
+
if persistent
|
|
67
|
+
post_init
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def persistent?
|
|
72
|
+
request.persistent?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def handle_error(error)
|
|
76
|
+
log_error error
|
|
77
|
+
close_connection rescue nil
|
|
78
|
+
rescue Exception => unexpected_error
|
|
79
|
+
log_error unexpected_error
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
protected
|
|
83
|
+
def guard_against_errors
|
|
84
|
+
yield
|
|
85
|
+
rescue RoutingError => e
|
|
86
|
+
handle_error e
|
|
87
|
+
rescue Exception => e
|
|
88
|
+
wrapped_error = Exception.new("Error in #{rack_request.path_info} : #{e.message}")
|
|
89
|
+
wrapped_error.set_backtrace(e.backtrace)
|
|
90
|
+
handle_error wrapped_error
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def get_resource
|
|
94
|
+
path_parts.inject(root_resource) do |resource, child_resource_name|
|
|
95
|
+
resource.locate(child_resource_name)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def root_resource
|
|
100
|
+
raise NotImplementedError
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def path_parts
|
|
104
|
+
rack_request.path_info.split('/').reject { |part| part == "" }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def error_message(e)
|
|
108
|
+
output = "Error in Connection#receive_line\n"
|
|
109
|
+
output << "#{e.message}\n"
|
|
110
|
+
output << e.backtrace.join("\n\t")
|
|
111
|
+
output << "\n\nResource was:\n\t"
|
|
112
|
+
output << "#{resource.inspect}\n"
|
|
113
|
+
output
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# From Mauricio Fernandez.
|
|
2
|
+
class Object
|
|
3
|
+
module InstanceExecHelper; end
|
|
4
|
+
include InstanceExecHelper
|
|
5
|
+
def instance_exec(*args, &block)
|
|
6
|
+
begin
|
|
7
|
+
old_critical, Thread.critical = Thread.critical, true
|
|
8
|
+
n = 0
|
|
9
|
+
n += 1 while respond_to?(mname="__instance_exec#{n}")
|
|
10
|
+
InstanceExecHelper.module_eval{ define_method(mname, &block) }
|
|
11
|
+
ensure
|
|
12
|
+
Thread.critical = old_critical
|
|
13
|
+
end
|
|
14
|
+
begin
|
|
15
|
+
ret = send(mname, *args)
|
|
16
|
+
ensure
|
|
17
|
+
InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
|
|
18
|
+
end
|
|
19
|
+
ret
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
module ThinRest
|
|
2
|
+
class Resource
|
|
3
|
+
class << self
|
|
4
|
+
def property(*names)
|
|
5
|
+
names.each do |name|
|
|
6
|
+
my_properties << name.to_sym
|
|
7
|
+
|
|
8
|
+
define_method name do
|
|
9
|
+
env[name]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
define_method "#{name}=" do |new_value|
|
|
13
|
+
env[name] = new_value
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def properties
|
|
19
|
+
if superclass.respond_to?(:properties)
|
|
20
|
+
superclass.properties | my_properties
|
|
21
|
+
else
|
|
22
|
+
my_properties
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def route(name, resource_type_name=nil, &block)
|
|
27
|
+
routes[name] = block || lambda do |env, name|
|
|
28
|
+
resource_type = resource_type_name.split('::').inject(Object) do |mod, next_mod_name|
|
|
29
|
+
mod.const_get(next_mod_name)
|
|
30
|
+
end
|
|
31
|
+
resource_type.new(env)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def routes
|
|
36
|
+
@routes ||= {}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
protected
|
|
40
|
+
def my_properties
|
|
41
|
+
@my_properties ||= []
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def handle_dequeue_and_process_error(command, error)
|
|
45
|
+
if command.connection
|
|
46
|
+
command.connection.handle_error error
|
|
47
|
+
else
|
|
48
|
+
super
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
ANY = Object.new
|
|
53
|
+
|
|
54
|
+
property :connection
|
|
55
|
+
attr_reader :env
|
|
56
|
+
|
|
57
|
+
def initialize(env={})
|
|
58
|
+
@env = env
|
|
59
|
+
env.each do |name, value|
|
|
60
|
+
if self.class.properties.include?(name.to_sym)
|
|
61
|
+
instance_variable_set("@#{name}", value)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
after_initialize
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def request; connection.request; end
|
|
68
|
+
def response; connection.response; end
|
|
69
|
+
def rack_request; connection.rack_request; end
|
|
70
|
+
|
|
71
|
+
def get
|
|
72
|
+
connection.send_head
|
|
73
|
+
connection.send_body(do_get || "")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def post
|
|
77
|
+
connection.send_head
|
|
78
|
+
connection.send_body(do_post || "")
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def put
|
|
82
|
+
connection.send_head
|
|
83
|
+
connection.send_body(do_put || "")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def delete
|
|
87
|
+
connection.send_head
|
|
88
|
+
connection.send_body(do_delete || "")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def locate(name)
|
|
92
|
+
route_handler = self.class.routes[name] || self.class.routes[ANY]
|
|
93
|
+
raise RoutingError, "Invalid route: #{connection.rack_request.path_info} ; name: #{name}" unless route_handler
|
|
94
|
+
instance_exec(env, name, &route_handler)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def unbind
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
protected
|
|
101
|
+
def after_initialize
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../thin_rest_spec_helper")
|
|
2
|
+
|
|
3
|
+
module ThinRest
|
|
4
|
+
describe Connection do
|
|
5
|
+
attr_reader :connection
|
|
6
|
+
|
|
7
|
+
describe "#process" do
|
|
8
|
+
attr_reader :result
|
|
9
|
+
before do
|
|
10
|
+
@connection = create_connection
|
|
11
|
+
stub(connection).socket_address {'0.0.0.0'}
|
|
12
|
+
|
|
13
|
+
@result = ""
|
|
14
|
+
stub(EventMachine).send_data do |signature, data, data_length|
|
|
15
|
+
result << data
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
context "when the call is successful" do
|
|
20
|
+
context "when the request has Connection: close" do
|
|
21
|
+
it "sends the response to the socket with a Connection: close response header" do
|
|
22
|
+
mock(connection).close_connection_after_writing
|
|
23
|
+
connection.receive_data "GET /subresource HTTP/1.1\r\nConnection: close\r\nHost: _\r\n\r\n"
|
|
24
|
+
result.should include("GET response")
|
|
25
|
+
result.should include("Connection: close")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "closes the connection" do
|
|
29
|
+
mock(connection).close_connection_after_writing
|
|
30
|
+
connection.receive_data "GET /subresource HTTP/1.1\r\nConnection: close\r\nHost: _\r\n\r\n"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "when the request does not have Connection: close" do
|
|
35
|
+
it "sends the response to the socket without a Connection: close response header" do
|
|
36
|
+
connection.receive_data "GET /subresource HTTP/1.1\r\nHost: _\r\n\r\n"
|
|
37
|
+
result.should include("GET response")
|
|
38
|
+
result.should_not include("Connection: close")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "does not close the connection" do
|
|
42
|
+
dont_allow(connection).close_connection_after_writing
|
|
43
|
+
connection.receive_data "GET /subresource HTTP/1.1\r\nHost: _\r\n\r\n"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context "when a second request is made" do
|
|
47
|
+
it "sends the response for the second request and not for the first request" do
|
|
48
|
+
connection.receive_data "GET /subresource HTTP/1.1\r\nHost: _\r\n\r\n"
|
|
49
|
+
result.should include("GET response")
|
|
50
|
+
result.should_not include("Another GET response")
|
|
51
|
+
|
|
52
|
+
connection.receive_data "GET /another_subresource HTTP/1.1\r\nHost: _\r\n\r\n"
|
|
53
|
+
result.should include("Another GET response")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context "when the call raises an error" do
|
|
60
|
+
it "logs the error and closes the connection" do
|
|
61
|
+
error = nil
|
|
62
|
+
mock(connection).log_error(is_a(Exception)) do |error_arg|
|
|
63
|
+
error = error_arg
|
|
64
|
+
end
|
|
65
|
+
mock(connection).close_connection
|
|
66
|
+
|
|
67
|
+
connection.receive_data "GET /error_subresource HTTP/1.1\r\nHost: _\r\n\r\n"
|
|
68
|
+
error.message.should =~ Regexp.new("/error_subresource")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe "#send_head" do
|
|
74
|
+
before do
|
|
75
|
+
@connection = create_connection
|
|
76
|
+
stub(EventMachine).close_connection
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
context "when passed no arguments" do
|
|
80
|
+
it "responds with a 200 HTTP header excluding the Content-Length" do
|
|
81
|
+
expected_header = "HTTP/1.1 200 OK\r\nServer: Thin Rest Server\r\n"
|
|
82
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
83
|
+
connection.send_head
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context "when passed 301" do
|
|
88
|
+
it "responds with a 301 HTTP header excluding the Content-Length" do
|
|
89
|
+
expected_header = "HTTP/1.1 301 OK\r\nServer: Thin Rest Server\r\n"
|
|
90
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
91
|
+
connection.send_head(301)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context "when passed additional parameters" do
|
|
96
|
+
it "responds with the additional parameters in the header" do
|
|
97
|
+
expected_header = "HTTP/1.1 301 OK\r\nServer: Thin Rest Server\r\nLocation: http://google.com\r\n"
|
|
98
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
99
|
+
connection.send_head(301, :Location => "http://google.com")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context "when not passed Content-length" do
|
|
103
|
+
it 'does not end with \r\n\r\n' do
|
|
104
|
+
expected_header = "HTTP/1.1 301 OK\r\nServer: Thin Rest Server\r\nLocation: http://google.com\r\n"
|
|
105
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
106
|
+
connection.send_head(301, :Location => "http://google.com")
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
context "when passed Content-Length" do
|
|
111
|
+
it 'when passed a Symbol representation of Content-Length ends with \r\n\r\n' do
|
|
112
|
+
expected_header = "HTTP/1.1 301 OK\r\nServer: Thin Rest Server\r\nContent-Length: 10\r\n\r\n"
|
|
113
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
114
|
+
connection.send_head(301, :'Content-Length' => 10)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it 'when passed a String representation of Content-Length ends with \r\n\r\n' do
|
|
118
|
+
expected_header = "HTTP/1.1 301 OK\r\nServer: Thin Rest Server\r\nContent-Length: 10\r\n\r\n"
|
|
119
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
120
|
+
connection.send_head(301, 'Content-Length' => 10)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
describe "#send_body" do
|
|
127
|
+
before do
|
|
128
|
+
@connection = create_connection
|
|
129
|
+
stub(EventMachine).close_connection
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "responds with Content-Length and the body" do
|
|
133
|
+
data = "The data"
|
|
134
|
+
header = "Content-Length: #{data.length}\r\n\r\n"
|
|
135
|
+
|
|
136
|
+
mock(EventMachine).send_data( connection.signature, header, header.length ) {header.length}
|
|
137
|
+
mock(EventMachine).send_data( connection.signature, data, data.length ) {data.length}
|
|
138
|
+
|
|
139
|
+
connection.send_body data
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
describe "#unbind" do
|
|
144
|
+
attr_reader :game_session
|
|
145
|
+
|
|
146
|
+
before do
|
|
147
|
+
stub_send_data
|
|
148
|
+
stub(EventMachine).close_connection
|
|
149
|
+
@connection = create_connection
|
|
150
|
+
params = "param_1=1¶m_2=2"
|
|
151
|
+
body = "#{params}\r\n"
|
|
152
|
+
connection.receive_data("POST /subresource HTTP/1.1\r\nHost: _\r\n\r\n#{body}")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "calls connection_finished on the backend to protect against memory leaks" do
|
|
156
|
+
mock(connection.backend).connection_finished(connection)
|
|
157
|
+
connection.unbind
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it "does not send data or add a timer of any type" do
|
|
161
|
+
dont_allow(EventMachine).send_data
|
|
162
|
+
dont_allow(EventMachine).add_timer
|
|
163
|
+
|
|
164
|
+
connection.unbind
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe "#handle_error" do
|
|
169
|
+
before do
|
|
170
|
+
@connection = create_connection
|
|
171
|
+
Thin::Logging.silent = true
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "logs the error" do
|
|
175
|
+
error = RuntimeError.new("Unexpected Error")
|
|
176
|
+
stub(error).backtrace(caller)
|
|
177
|
+
|
|
178
|
+
stub(connection).warn
|
|
179
|
+
mock.proxy(connection).log_error(error)
|
|
180
|
+
mock.proxy(connection).log_error(anything)
|
|
181
|
+
|
|
182
|
+
connection.handle_error(error)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
describe "#persistent?" do
|
|
187
|
+
before do
|
|
188
|
+
@connection = create_connection
|
|
189
|
+
stub(connection).socket_address {'0.0.0.0'}
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
context "when #request.persistent? is true" do
|
|
193
|
+
it "returns true" do
|
|
194
|
+
stub(connection.request).persistent? {true}
|
|
195
|
+
connection.should be_persistent
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
context "when #request.persistent? is false" do
|
|
200
|
+
it "returns false" do
|
|
201
|
+
stub(connection.request).persistent? {false}
|
|
202
|
+
connection.should_not be_persistent
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|