pivotal-screw-unit 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. data/CHANGES +21 -0
  2. data/README.markdown +354 -0
  3. data/Rakefile +39 -0
  4. data/VERSION.yml +4 -0
  5. data/bin/screw_unit +6 -0
  6. data/bin/screw_unit_server +10 -0
  7. data/core/CHANGES +10 -0
  8. data/core/EXAMPLE.html +68 -0
  9. data/core/LICENSE +22 -0
  10. data/core/README.markdown +307 -0
  11. data/core/example/models/cat.js +5 -0
  12. data/core/example/models/man.js +17 -0
  13. data/core/example/spec/matchers/have.js +8 -0
  14. data/core/example/spec/models/cat_spec.js +31 -0
  15. data/core/example/spec/models/man_spec.js +34 -0
  16. data/core/example/spec/spec_helper.js +5 -0
  17. data/core/example/spec/suite.html +25 -0
  18. data/core/lib/jquery-1.3.2.js +4376 -0
  19. data/core/lib/jquery.fn.js +30 -0
  20. data/core/lib/jquery.print.js +109 -0
  21. data/core/lib/screw.behaviors.js +93 -0
  22. data/core/lib/screw.builder.js +94 -0
  23. data/core/lib/screw.css +90 -0
  24. data/core/lib/screw.events.js +45 -0
  25. data/core/lib/screw.matchers.js +244 -0
  26. data/core/spec/behaviors_spec.js +188 -0
  27. data/core/spec/matchers_spec.js +372 -0
  28. data/core/spec/print_spec.js +158 -0
  29. data/core/spec/spec_helper.js +0 -0
  30. data/core/spec/suite.html +19 -0
  31. data/core/spec/with_screw_context_spec.js +9 -0
  32. data/init.rb +0 -0
  33. data/lib/screw_unit/representations/spec.html.rb +117 -0
  34. data/lib/screw_unit/representations.rb +2 -0
  35. data/lib/screw_unit.rb +19 -0
  36. data/spec/functional/functional_spec.rb +25 -0
  37. data/spec/functional/functional_spec_helper.rb +34 -0
  38. data/spec/functional/functional_spec_server_starter.rb +63 -0
  39. data/spec/functional_suite.rb +10 -0
  40. data/spec/spec_suite.rb +3 -0
  41. data/spec/unit/js_test_core/specs/spec_dir_spec.rb +39 -0
  42. data/spec/unit/js_test_core/specs/spec_file_spec.rb +35 -0
  43. data/spec/unit/unit_spec_helper.rb +119 -0
  44. data/spec/unit_suite.rb +10 -0
  45. data/vendor/js-test-core/CHANGES +25 -0
  46. data/vendor/js-test-core/README +12 -0
  47. data/vendor/js-test-core/Rakefile +73 -0
  48. data/vendor/js-test-core/lib/js_test_core/client.rb +129 -0
  49. data/vendor/js-test-core/lib/js_test_core/extensions/time.rb +6 -0
  50. data/vendor/js-test-core/lib/js_test_core/extensions.rb +3 -0
  51. data/vendor/js-test-core/lib/js_test_core/rack/commonlogger.rb +5 -0
  52. data/vendor/js-test-core/lib/js_test_core/rack.rb +2 -0
  53. data/vendor/js-test-core/lib/js_test_core/rails_server.rb +22 -0
  54. data/vendor/js-test-core/lib/js_test_core/representations/spec.html.rb +23 -0
  55. data/vendor/js-test-core/lib/js_test_core/representations.rb +9 -0
  56. data/vendor/js-test-core/lib/js_test_core/resources/dir.rb +67 -0
  57. data/vendor/js-test-core/lib/js_test_core/resources/file.rb +42 -0
  58. data/vendor/js-test-core/lib/js_test_core/resources/runner.rb +107 -0
  59. data/vendor/js-test-core/lib/js_test_core/resources/session.rb +44 -0
  60. data/vendor/js-test-core/lib/js_test_core/resources/session_finish.rb +17 -0
  61. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec.rb +32 -0
  62. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_dir.rb +50 -0
  63. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_file.rb +21 -0
  64. data/vendor/js-test-core/lib/js_test_core/resources/web_root.rb +66 -0
  65. data/vendor/js-test-core/lib/js_test_core/resources.rb +17 -0
  66. data/vendor/js-test-core/lib/js_test_core/selenium/client/driver.rb +7 -0
  67. data/vendor/js-test-core/lib/js_test_core/selenium.rb +2 -0
  68. data/vendor/js-test-core/lib/js_test_core/selenium_server_configuration.rb +48 -0
  69. data/vendor/js-test-core/lib/js_test_core/server.rb +50 -0
  70. data/vendor/js-test-core/lib/js_test_core/thin/backends/js_test_core_server.rb +9 -0
  71. data/vendor/js-test-core/lib/js_test_core/thin/js_test_core_connection.rb +8 -0
  72. data/vendor/js-test-core/lib/js_test_core/thin.rb +3 -0
  73. data/vendor/js-test-core/lib/js_test_core.rb +41 -0
  74. data/vendor/js-test-core/spec/example_core/JsTestCore.css +0 -0
  75. data/vendor/js-test-core/spec/example_core/JsTestCore.js +0 -0
  76. data/vendor/js-test-core/spec/example_public/favicon.ico +0 -0
  77. data/vendor/js-test-core/spec/example_public/javascripts/foo.js +3 -0
  78. data/vendor/js-test-core/spec/example_public/javascripts/large_file.js +59 -0
  79. data/vendor/js-test-core/spec/example_public/javascripts/subdir/bar.js +1 -0
  80. data/vendor/js-test-core/spec/example_public/robots.txt +0 -0
  81. data/vendor/js-test-core/spec/example_public/stylesheets/example.css +3 -0
  82. data/vendor/js-test-core/spec/example_specs/custom_dir_and_suite/passing_spec.js +6 -0
  83. data/vendor/js-test-core/spec/example_specs/custom_dir_and_suite.html +9 -0
  84. data/vendor/js-test-core/spec/example_specs/custom_suite.html +8 -0
  85. data/vendor/js-test-core/spec/example_specs/failing_spec.js +5 -0
  86. data/vendor/js-test-core/spec/example_specs/foo/failing_spec.js +6 -0
  87. data/vendor/js-test-core/spec/example_specs/foo/passing_spec.js +6 -0
  88. data/vendor/js-test-core/spec/spec_suite.rb +2 -0
  89. data/vendor/js-test-core/spec/specs/failing_spec.js +0 -0
  90. data/vendor/js-test-core/spec/unit/js_test_core/client_spec.rb +192 -0
  91. data/vendor/js-test-core/spec/unit/js_test_core/rails_server_spec.rb +45 -0
  92. data/vendor/js-test-core/spec/unit/js_test_core/resources/dir_spec.rb +53 -0
  93. data/vendor/js-test-core/spec/unit/js_test_core/resources/file_not_found_spec.rb +16 -0
  94. data/vendor/js-test-core/spec/unit/js_test_core/resources/file_spec.rb +90 -0
  95. data/vendor/js-test-core/spec/unit/js_test_core/resources/runners/runner_spec.rb +303 -0
  96. data/vendor/js-test-core/spec/unit/js_test_core/resources/session_finish_spec.rb +79 -0
  97. data/vendor/js-test-core/spec/unit/js_test_core/resources/session_spec.rb +82 -0
  98. data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_dir_spec.rb +104 -0
  99. data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_file_spec.rb +41 -0
  100. data/vendor/js-test-core/spec/unit/js_test_core/resources/web_root_spec.rb +32 -0
  101. data/vendor/js-test-core/spec/unit/js_test_core/selenium_server_configuration_spec.rb +49 -0
  102. data/vendor/js-test-core/spec/unit/js_test_core/server_spec.rb +117 -0
  103. data/vendor/js-test-core/spec/unit/thin/js_test_core_connection_spec.rb +6 -0
  104. data/vendor/js-test-core/spec/unit/unit_spec_helper.rb +161 -0
  105. data/vendor/js-test-core/spec/unit_suite.rb +10 -0
  106. data/vendor/js-test-core/vendor/thin-rest/CHANGES +2 -0
  107. data/vendor/js-test-core/vendor/thin-rest/README +0 -0
  108. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/connection.rb +117 -0
  109. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/extensions/object.rb +21 -0
  110. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/extensions.rb +3 -0
  111. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/representations/internal_error.html.rb +19 -0
  112. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/representations/page.html.rb +41 -0
  113. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/representations/resource_not_found.html.rb +18 -0
  114. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/representations.rb +4 -0
  115. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resources/internal_error.rb +11 -0
  116. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resources/resource.rb +105 -0
  117. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resources/resource_not_found.rb +19 -0
  118. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resources.rb +4 -0
  119. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/routing_error.rb +5 -0
  120. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest.rb +10 -0
  121. data/vendor/js-test-core/vendor/thin-rest/spec/spec_suite.rb +5 -0
  122. data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/connection_spec.rb +205 -0
  123. data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/resources/resource_not_found_spec.rb +16 -0
  124. data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/resources/resource_spec.rb +135 -0
  125. data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/resources/root_spec.rb +16 -0
  126. data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest_spec_helper.rb +133 -0
  127. metadata +184 -0
@@ -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,18 @@
1
+ module ThinRest
2
+ module Representations
3
+ class ResourceNotFound < Page
4
+ protected
5
+ def body_content
6
+ h1 message
7
+ end
8
+
9
+ def title_text
10
+ message
11
+ end
12
+
13
+ def message
14
+ "File #{path} not found"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,4 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/representations/page.html"
3
+ require "#{dir}/representations/internal_error.html"
4
+ require "#{dir}/representations/resource_not_found.html"
@@ -0,0 +1,11 @@
1
+ module ThinRest
2
+ module Resources
3
+ class InternalError < Resource
4
+ property :error
5
+ def get
6
+ connection.send_head(500)
7
+ connection.send_body(Representations::InternalError.new(self, :error => error).to_s)
8
+ end
9
+ end
10
+ end
11
+ 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,4 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/resources/resource"
3
+ require "#{dir}/resources/internal_error"
4
+ require "#{dir}/resources/resource_not_found"
@@ -0,0 +1,5 @@
1
+ module ThinRest
2
+ class RoutingError < RuntimeError
3
+
4
+ end
5
+ 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,5 @@
1
+ dir = File.dirname(__FILE__)
2
+ Dir["#{dir}/**/*_spec.rb"].each do |file|
3
+ # puts "require '#{file}'"
4
+ require file
5
+ end
@@ -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&param_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