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.
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