pivotal-screw-unit 0.4.0
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 +21 -0
- data/README.markdown +354 -0
- data/Rakefile +39 -0
- data/VERSION.yml +4 -0
- data/bin/screw_unit +6 -0
- data/bin/screw_unit_server +10 -0
- data/core/CHANGES +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.3.2.js +4376 -0
- data/core/lib/jquery.fn.js +30 -0
- data/core/lib/jquery.print.js +109 -0
- data/core/lib/screw.behaviors.js +93 -0
- data/core/lib/screw.builder.js +94 -0
- data/core/lib/screw.css +90 -0
- data/core/lib/screw.events.js +45 -0
- data/core/lib/screw.matchers.js +244 -0
- data/core/spec/behaviors_spec.js +188 -0
- data/core/spec/matchers_spec.js +372 -0
- data/core/spec/print_spec.js +158 -0
- data/core/spec/spec_helper.js +0 -0
- data/core/spec/suite.html +19 -0
- data/core/spec/with_screw_context_spec.js +9 -0
- data/init.rb +0 -0
- data/lib/screw_unit/representations/spec.html.rb +117 -0
- data/lib/screw_unit/representations.rb +2 -0
- data/lib/screw_unit.rb +19 -0
- data/spec/functional/functional_spec.rb +25 -0
- data/spec/functional/functional_spec_helper.rb +34 -0
- data/spec/functional/functional_spec_server_starter.rb +63 -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 +119 -0
- data/spec/unit_suite.rb +10 -0
- data/vendor/js-test-core/CHANGES +25 -0
- data/vendor/js-test-core/README +12 -0
- data/vendor/js-test-core/Rakefile +73 -0
- data/vendor/js-test-core/lib/js_test_core/client.rb +129 -0
- data/vendor/js-test-core/lib/js_test_core/extensions/time.rb +6 -0
- data/vendor/js-test-core/lib/js_test_core/extensions.rb +3 -0
- data/vendor/js-test-core/lib/js_test_core/rack/commonlogger.rb +5 -0
- data/vendor/js-test-core/lib/js_test_core/rack.rb +2 -0
- data/vendor/js-test-core/lib/js_test_core/rails_server.rb +22 -0
- data/vendor/js-test-core/lib/js_test_core/representations/spec.html.rb +23 -0
- data/vendor/js-test-core/lib/js_test_core/representations.rb +9 -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 +42 -0
- data/vendor/js-test-core/lib/js_test_core/resources/runner.rb +107 -0
- data/vendor/js-test-core/lib/js_test_core/resources/session.rb +44 -0
- data/vendor/js-test-core/lib/js_test_core/resources/session_finish.rb +17 -0
- data/vendor/js-test-core/lib/js_test_core/resources/specs/spec.rb +32 -0
- data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_dir.rb +50 -0
- data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_file.rb +21 -0
- data/vendor/js-test-core/lib/js_test_core/resources/web_root.rb +66 -0
- data/vendor/js-test-core/lib/js_test_core/resources.rb +17 -0
- data/vendor/js-test-core/lib/js_test_core/selenium/client/driver.rb +7 -0
- data/vendor/js-test-core/lib/js_test_core/selenium.rb +2 -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/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/lib/js_test_core/thin.rb +3 -0
- data/vendor/js-test-core/lib/js_test_core.rb +41 -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/custom_dir_and_suite/passing_spec.js +6 -0
- data/vendor/js-test-core/spec/example_specs/custom_dir_and_suite.html +9 -0
- data/vendor/js-test-core/spec/example_specs/custom_suite.html +8 -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 +192 -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 +53 -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 +90 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/runners/runner_spec.rb +303 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/session_finish_spec.rb +79 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/session_spec.rb +82 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_dir_spec.rb +104 -0
- data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_file_spec.rb +41 -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 +161 -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/connection.rb +117 -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/extensions.rb +3 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/representations/internal_error.html.rb +19 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/representations/page.html.rb +41 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/representations/resource_not_found.html.rb +18 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/representations.rb +4 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resources/internal_error.rb +11 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resources/resource.rb +105 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resources/resource_not_found.rb +19 -0
- data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resources.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/lib/thin_rest.rb +10 -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 +205 -0
- data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/resources/resource_not_found_spec.rb +16 -0
- data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/resources/resource_spec.rb +135 -0
- data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/resources/root_spec.rb +16 -0
- data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest_spec_helper.rb +133 -0
- metadata +184 -0
data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/representations/internal_error.html.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module ThinRest
|
|
2
|
+
module Representations
|
|
3
|
+
class InternalError < Page
|
|
4
|
+
protected
|
|
5
|
+
def body_content
|
|
6
|
+
h1 error.message
|
|
7
|
+
ul do
|
|
8
|
+
error.backtrace.split("\n").each do |line|
|
|
9
|
+
li line
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def title_text
|
|
15
|
+
error.message
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module ThinRest
|
|
2
|
+
module Representations
|
|
3
|
+
class Page < Erector::Widget
|
|
4
|
+
def render(&block)
|
|
5
|
+
rawtext %Q{<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">}
|
|
6
|
+
html :xmlns => "http://www.w3.org/1999/xhtml", :"xml:lang" => "en" do
|
|
7
|
+
head do
|
|
8
|
+
meta :"http-equiv" => "Content-Type", :content => "text/html;charset=UTF-8"
|
|
9
|
+
title title_text
|
|
10
|
+
head_content
|
|
11
|
+
end
|
|
12
|
+
body do
|
|
13
|
+
body_content(&block)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
protected
|
|
19
|
+
def head_content
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def title_text
|
|
23
|
+
"Thin Rest"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def body_content(&block)
|
|
27
|
+
yield(self)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def path
|
|
31
|
+
helpers.rack_request.path_info
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def script_elements
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def link_elements
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module ThinRest
|
|
2
|
+
module Resources
|
|
3
|
+
class Resource
|
|
4
|
+
class << self
|
|
5
|
+
def property(*names)
|
|
6
|
+
names.each do |name|
|
|
7
|
+
my_properties << name.to_sym
|
|
8
|
+
|
|
9
|
+
define_method name do
|
|
10
|
+
env[name]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
define_method "#{name}=" do |new_value|
|
|
14
|
+
env[name] = new_value
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def properties
|
|
20
|
+
if superclass.respond_to?(:properties)
|
|
21
|
+
superclass.properties | my_properties
|
|
22
|
+
else
|
|
23
|
+
my_properties
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def route(name, resource_type_name=nil, &block)
|
|
28
|
+
routes[name] = block || lambda do |env, name|
|
|
29
|
+
resource_type = resource_type_name.split('::').inject(Object) do |mod, next_mod_name|
|
|
30
|
+
mod.const_get(next_mod_name)
|
|
31
|
+
end
|
|
32
|
+
resource_type.new(env)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def routes
|
|
37
|
+
@routes ||= {}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
protected
|
|
41
|
+
def my_properties
|
|
42
|
+
@my_properties ||= []
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def handle_dequeue_and_process_error(command, error)
|
|
46
|
+
if command.connection
|
|
47
|
+
command.connection.handle_error error
|
|
48
|
+
else
|
|
49
|
+
super
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
ANY = Object.new
|
|
54
|
+
|
|
55
|
+
property :connection
|
|
56
|
+
attr_reader :env
|
|
57
|
+
|
|
58
|
+
def initialize(env={})
|
|
59
|
+
@env = env
|
|
60
|
+
env.each do |name, value|
|
|
61
|
+
if self.class.properties.include?(name.to_sym)
|
|
62
|
+
instance_variable_set("@#{name}", value)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
after_initialize
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def request; connection.request; end
|
|
69
|
+
def response; connection.response; end
|
|
70
|
+
def rack_request; connection.rack_request; end
|
|
71
|
+
|
|
72
|
+
def get
|
|
73
|
+
connection.send_head
|
|
74
|
+
connection.send_body(do_get || "")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def post
|
|
78
|
+
connection.send_head
|
|
79
|
+
connection.send_body(do_post || "")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def put
|
|
83
|
+
connection.send_head
|
|
84
|
+
connection.send_body(do_put || "")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def delete
|
|
88
|
+
connection.send_head
|
|
89
|
+
connection.send_body(do_delete || "")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def locate(name)
|
|
93
|
+
route_handler = self.class.routes[name] || self.class.routes[ANY] || ResourceNotFound.method(:default_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
|
|
105
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module ThinRest
|
|
2
|
+
module Resources
|
|
3
|
+
class ResourceNotFound < Resource
|
|
4
|
+
class << self
|
|
5
|
+
def default_handler(env, name)
|
|
6
|
+
new(env)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
property :name
|
|
11
|
+
def get
|
|
12
|
+
connection.send_head(404)
|
|
13
|
+
connection.send_body(Representations::ResourceNotFound.new(self).to_s) do
|
|
14
|
+
raise RoutingError, "Invalid route: #{connection.rack_request.path_info} ; name: #{name}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
require "rubygems"
|
|
2
|
+
require "thin"
|
|
3
|
+
require "erector"
|
|
4
|
+
|
|
5
|
+
dir = File.dirname(__FILE__)
|
|
6
|
+
require "#{dir}/thin_rest/connection"
|
|
7
|
+
require "#{dir}/thin_rest/resources"
|
|
8
|
+
require "#{dir}/thin_rest/representations"
|
|
9
|
+
require "#{dir}/thin_rest/routing_error"
|
|
10
|
+
require "#{dir}/thin_rest/extensions"
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../thin_rest_spec_helper")
|
|
2
|
+
|
|
3
|
+
module ThinRest
|
|
4
|
+
describe Connection do
|
|
5
|
+
describe "#process" do
|
|
6
|
+
attr_reader :result
|
|
7
|
+
before do
|
|
8
|
+
stub(connection).socket_address {'0.0.0.0'}
|
|
9
|
+
|
|
10
|
+
@result = ""
|
|
11
|
+
stub(EventMachine).send_data do |signature, data, data_length|
|
|
12
|
+
result << data
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context "when the call is successful" do
|
|
17
|
+
context "when the request has Connection: close" do
|
|
18
|
+
it "sends the response to the socket with a Connection: close response header" do
|
|
19
|
+
mock(connection).close_connection_after_writing
|
|
20
|
+
connection.receive_data "GET /subresource HTTP/1.1\r\nConnection: close\r\nHost: _\r\n\r\n"
|
|
21
|
+
result.should include("GET response")
|
|
22
|
+
result.should include("Connection: close")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "closes the connection" do
|
|
26
|
+
mock(connection).close_connection_after_writing
|
|
27
|
+
connection.receive_data "GET /subresource HTTP/1.1\r\nConnection: close\r\nHost: _\r\n\r\n"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context "when the request does not have Connection: close" do
|
|
32
|
+
it "sends the response to the socket without a Connection: close response header" do
|
|
33
|
+
connection.receive_data "GET /subresource HTTP/1.1\r\nHost: _\r\n\r\n"
|
|
34
|
+
result.should include("GET response")
|
|
35
|
+
result.should_not include("Connection: close")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "does not close the connection" do
|
|
39
|
+
dont_allow(connection).close_connection_after_writing
|
|
40
|
+
connection.receive_data "GET /subresource HTTP/1.1\r\nHost: _\r\n\r\n"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context "when a second request is made" do
|
|
44
|
+
it "sends the response for the second request and not for the first request" do
|
|
45
|
+
connection.receive_data "GET /subresource HTTP/1.1\r\nHost: _\r\n\r\n"
|
|
46
|
+
result.should include("GET response")
|
|
47
|
+
result.should_not include("Another GET response")
|
|
48
|
+
|
|
49
|
+
connection.receive_data "GET /another_subresource HTTP/1.1\r\nHost: _\r\n\r\n"
|
|
50
|
+
result.should include("Another GET response")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context "when the call raises an error" do
|
|
57
|
+
it "responds with a 500 page and logs the error" do
|
|
58
|
+
error = nil
|
|
59
|
+
mock(connection).log_error(is_a(Exception)) do |error_arg|
|
|
60
|
+
error = error_arg
|
|
61
|
+
end
|
|
62
|
+
mock(connection).send_head(500)
|
|
63
|
+
mock(connection).send_body(Regexp.new(ErrorSubresource::ERROR_MESSAGE))
|
|
64
|
+
|
|
65
|
+
connection.receive_data "GET /error_subresource HTTP/1.1\r\nHost: _\r\n\r\n"
|
|
66
|
+
error.message.should =~ Regexp.new("/error_subresource")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe "#send_head" do
|
|
72
|
+
before do
|
|
73
|
+
@connection = create_connection
|
|
74
|
+
stub(EventMachine).close_connection
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context "when passed no arguments" do
|
|
78
|
+
it "responds with a 200 HTTP header excluding the Content-Length" do
|
|
79
|
+
expected_header = "HTTP/1.1 200 OK\r\nServer: Thin Rest Server\r\n"
|
|
80
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
81
|
+
connection.send_head
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context "when passed 301" do
|
|
86
|
+
it "responds with a 301 HTTP header excluding the Content-Length" do
|
|
87
|
+
expected_header = "HTTP/1.1 301 OK\r\nServer: Thin Rest Server\r\n"
|
|
88
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
89
|
+
connection.send_head(301)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context "when passed additional parameters" do
|
|
94
|
+
it "responds with the additional parameters in the header" do
|
|
95
|
+
expected_header = "HTTP/1.1 301 OK\r\nServer: Thin Rest Server\r\nLocation: http://google.com\r\n"
|
|
96
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
97
|
+
connection.send_head(301, :Location => "http://google.com")
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context "when not passed Content-length" do
|
|
101
|
+
it 'does not end with \r\n\r\n' do
|
|
102
|
+
expected_header = "HTTP/1.1 301 OK\r\nServer: Thin Rest Server\r\nLocation: http://google.com\r\n"
|
|
103
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
104
|
+
connection.send_head(301, :Location => "http://google.com")
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
context "when passed Content-Length" do
|
|
109
|
+
it 'when passed a Symbol representation of Content-Length ends with \r\n\r\n' do
|
|
110
|
+
expected_header = "HTTP/1.1 301 OK\r\nServer: Thin Rest Server\r\nContent-Length: 10\r\n\r\n"
|
|
111
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
112
|
+
connection.send_head(301, :'Content-Length' => 10)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'when passed a String representation of Content-Length ends with \r\n\r\n' do
|
|
116
|
+
expected_header = "HTTP/1.1 301 OK\r\nServer: Thin Rest Server\r\nContent-Length: 10\r\n\r\n"
|
|
117
|
+
mock(EventMachine).send_data( connection.signature, expected_header, expected_header.length ) {expected_header.length}
|
|
118
|
+
connection.send_head(301, 'Content-Length' => 10)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
describe "#send_body" do
|
|
125
|
+
before do
|
|
126
|
+
@connection = create_connection
|
|
127
|
+
stub(EventMachine).close_connection
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "responds with Content-Length and the body" do
|
|
131
|
+
data = "The data"
|
|
132
|
+
header = "Content-Length: #{data.length}\r\n\r\n"
|
|
133
|
+
|
|
134
|
+
mock(EventMachine).send_data( connection.signature, header, header.length ) {header.length}
|
|
135
|
+
mock(EventMachine).send_data( connection.signature, data, data.length ) {data.length}
|
|
136
|
+
|
|
137
|
+
connection.send_body data
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe "#unbind" do
|
|
142
|
+
attr_reader :game_session
|
|
143
|
+
|
|
144
|
+
before do
|
|
145
|
+
stub_send_data
|
|
146
|
+
stub(EventMachine).close_connection
|
|
147
|
+
@connection = create_connection
|
|
148
|
+
params = "param_1=1¶m_2=2"
|
|
149
|
+
body = "#{params}\r\n"
|
|
150
|
+
connection.receive_data("POST /subresource HTTP/1.1\r\nHost: _\r\n\r\n#{body}")
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it "calls connection_finished on the backend to protect against memory leaks" do
|
|
154
|
+
mock(connection.backend).connection_finished(connection)
|
|
155
|
+
connection.unbind
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it "does not send data or add a timer of any type" do
|
|
159
|
+
dont_allow(EventMachine).send_data
|
|
160
|
+
dont_allow(EventMachine).add_timer
|
|
161
|
+
|
|
162
|
+
connection.unbind
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
describe "#handle_error" do
|
|
167
|
+
before do
|
|
168
|
+
@connection = create_connection
|
|
169
|
+
Thin::Logging.silent = true
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "logs the error" do
|
|
173
|
+
error = RuntimeError.new("Unexpected Error")
|
|
174
|
+
stub(error).backtrace(caller)
|
|
175
|
+
|
|
176
|
+
stub(connection).warn
|
|
177
|
+
mock.proxy(connection).log_error(error)
|
|
178
|
+
mock.proxy(connection).log_error(anything)
|
|
179
|
+
|
|
180
|
+
connection.handle_error(error)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
describe "#persistent?" do
|
|
185
|
+
before do
|
|
186
|
+
@connection = create_connection
|
|
187
|
+
stub(connection).socket_address {'0.0.0.0'}
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
context "when #request.persistent? is true" do
|
|
191
|
+
it "returns true" do
|
|
192
|
+
stub(connection.request).persistent? {true}
|
|
193
|
+
connection.should be_persistent
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
context "when #request.persistent? is false" do
|
|
198
|
+
it "returns false" do
|
|
199
|
+
stub(connection.request).persistent? {false}
|
|
200
|
+
connection.should_not be_persistent
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../thin_rest_spec_helper")
|
|
2
|
+
|
|
3
|
+
module ThinRest
|
|
4
|
+
module Resources
|
|
5
|
+
describe ResourceNotFound do
|
|
6
|
+
describe "GET /invalid_path" do
|
|
7
|
+
it "returns a page with a of files in the directory" do
|
|
8
|
+
mock(connection).send_head(404)
|
|
9
|
+
mock(connection).send_body(Regexp.new("File /invalid_path not found."))
|
|
10
|
+
|
|
11
|
+
connection.receive_data("GET /invalid_path HTTP/1.1\r\nHost: _\r\n\r\n")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../thin_rest_spec_helper")
|
|
2
|
+
|
|
3
|
+
module ThinRest
|
|
4
|
+
module Resources
|
|
5
|
+
describe Resource do
|
|
6
|
+
attr_reader :root
|
|
7
|
+
self.thin_logging = true
|
|
8
|
+
before do
|
|
9
|
+
stub(EventMachine).close_connection
|
|
10
|
+
@root = Root.new(:connection => connection)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe ".property" do
|
|
14
|
+
it "creates a reader that takes its value from its env property" do
|
|
15
|
+
root.env[:connection].should == connection
|
|
16
|
+
root.connection.should == root.env[:connection]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "creates a writer that sets its passed in value to its env property" do
|
|
20
|
+
another_connection = create_connection
|
|
21
|
+
root.connection = another_connection
|
|
22
|
+
root.connection.should == another_connection
|
|
23
|
+
root.env[:connection].should == another_connection
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe "#locate" do
|
|
28
|
+
context "/subresource - route is defined using a String" do
|
|
29
|
+
it "returns an instance of Subresource" do
|
|
30
|
+
root.locate("subresource").class.should == Subresource
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "/block_subresource - route is defined using a block" do
|
|
35
|
+
it "returns an instance of BlockSubresource" do
|
|
36
|
+
root.locate("block_subresource").class.should == BlockSubresource
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "executes the block within the instance of the Resource" do
|
|
40
|
+
root.foobar.should_not be_nil
|
|
41
|
+
root.locate("block_subresource").foobar.should == root.foobar
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context "/no_handler_subresource - route is not defined" do
|
|
46
|
+
it "returns a ResourceNotFound resource" do
|
|
47
|
+
root.locate("no_handler_subresource").class.should == Resources::ResourceNotFound
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context "/wrong_property - passed in property not defined" do
|
|
52
|
+
it "does not set an instance variable named after the wrong property" do
|
|
53
|
+
resource = root.locate("wrong_property")
|
|
54
|
+
resource.env.should == {:connection => connection, :baz => "wrong_property"}
|
|
55
|
+
resource.instance_variable_get("@connection").should == connection
|
|
56
|
+
resource.instance_variable_get("@baz").should be_nil
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe "Delegations" do
|
|
62
|
+
describe "#request" do
|
|
63
|
+
it "delegates to #connection" do
|
|
64
|
+
root.request.should == connection.request
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe "#response" do
|
|
69
|
+
it "delegates to #connection" do
|
|
70
|
+
root.response.should == connection.response
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe "#rack_request" do
|
|
75
|
+
it "delegates to #connection" do
|
|
76
|
+
root.rack_request.should == connection.rack_request
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
describe "GET /subresource" do
|
|
82
|
+
it "sends the GET response for the resource" do
|
|
83
|
+
mock(connection).send_data(connection.head(200, {}))
|
|
84
|
+
expected_data = "GET response"
|
|
85
|
+
expected_content_length = "Content-Length: #{expected_data.length}\r\n\r\n"
|
|
86
|
+
mock(connection).send_data(expected_content_length) {expected_content_length.length}
|
|
87
|
+
mock(connection).send_data(expected_data) {expected_data.length}
|
|
88
|
+
connection.receive_data("GET /subresource HTTP/1.1\r\nHost: _\r\n\r\n")
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe "GET /no_handler_subresource" do
|
|
93
|
+
it "renders an error page and logs the error" do
|
|
94
|
+
stub(connection).send_data
|
|
95
|
+
mock(connection).send_data(Regexp.new("File /no_handler_subresource not found"))
|
|
96
|
+
mock(connection).log_error(is_a(ThinRest::RoutingError))
|
|
97
|
+
connection.receive_data("GET /no_handler_subresource HTTP/1.1\r\nHost: _\r\n\r\n")
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe "POST /subresource" do
|
|
102
|
+
it "sends the POST response for the resource" do
|
|
103
|
+
mock(connection).send_data(connection.head(200, {}))
|
|
104
|
+
expected_data = "POST response"
|
|
105
|
+
expected_content_length = "Content-Length: #{expected_data.length}\r\n\r\n"
|
|
106
|
+
mock(connection).send_data(expected_content_length) {expected_content_length.length}
|
|
107
|
+
mock(connection).send_data(expected_data) {expected_data.length}
|
|
108
|
+
connection.receive_data("POST /subresource HTTP/1.1\r\nHost: _\r\n\r\n")
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe "PUT /subresource" do
|
|
113
|
+
it "sends the PUT response for the resource" do
|
|
114
|
+
mock(connection).send_data(connection.head(200, {}))
|
|
115
|
+
expected_data = "PUT response"
|
|
116
|
+
expected_content_length = "Content-Length: #{expected_data.length}\r\n\r\n"
|
|
117
|
+
mock(connection).send_data(expected_content_length) {expected_content_length.length}
|
|
118
|
+
mock(connection).send_data(expected_data) {expected_data.length}
|
|
119
|
+
connection.receive_data("PUT /subresource HTTP/1.1\r\nHost: _\r\n\r\n")
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
describe "DELETE /subresource" do
|
|
124
|
+
it "sends the DELETE response for the resource" do
|
|
125
|
+
mock(connection).send_data(connection.head(200, {}))
|
|
126
|
+
expected_data = "DELETE response"
|
|
127
|
+
expected_content_length = "Content-Length: #{expected_data.length}\r\n\r\n"
|
|
128
|
+
mock(connection).send_data(expected_content_length) {expected_content_length.length}
|
|
129
|
+
mock(connection).send_data(expected_data) {expected_data.length}
|
|
130
|
+
connection.receive_data("DELETE /subresource HTTP/1.1\r\nHost: _\r\n\r\n")
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../thin_rest_spec_helper")
|
|
2
|
+
|
|
3
|
+
module ThinRest
|
|
4
|
+
module Resources
|
|
5
|
+
describe ResourceNotFound do
|
|
6
|
+
describe "GET /invalid_path" do
|
|
7
|
+
it "returns a page with a of files in the directory" do
|
|
8
|
+
mock(connection).send_head(404)
|
|
9
|
+
mock(connection).send_body(Regexp.new("File /invalid_path not found."))
|
|
10
|
+
|
|
11
|
+
connection.receive_data("GET /invalid_path HTTP/1.1\r\nHost: _\r\n\r\n")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|