fastr 0.0.3 → 0.1.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/README.rdoc +182 -6
- data/bin/fastr +46 -10
- data/lib/fastr.rb +5 -0
- data/lib/fastr/application.rb +59 -152
- data/lib/fastr/async.rb +11 -0
- data/lib/fastr/controller.rb +67 -24
- data/lib/fastr/cookie.rb +37 -0
- data/lib/fastr/deferrable.rb +9 -9
- data/lib/fastr/dispatch.rb +151 -0
- data/lib/fastr/extensions/string.rb +8 -0
- data/lib/fastr/filter.rb +118 -11
- data/lib/fastr/http.rb +58 -0
- data/lib/fastr/plugin.rb +8 -8
- data/lib/fastr/router.rb +56 -7
- data/lib/fastr/settings.rb +9 -5
- data/lib/fastr/template.rb +83 -24
- data/lib/fastr/template/erubis.rb +23 -0
- data/lib/fastr/template/haml.rb +23 -0
- data/lib/fastr/test.rb +9 -0
- data/lib/fastr/test/application.rb +25 -0
- data/lib/fastr/test/controller.rb +78 -0
- data/lib/fastr/test/logger.rb +5 -0
- data/lib/fastr/test/tasks.rb +3 -0
- data/lib/fastr/test/tasks/test.rake +10 -0
- data/test/fastr_app/app/config/settings.rb +1 -0
- data/test/fastr_app/app/controllers/dispatch.rb +31 -0
- data/test/helper.rb +6 -4
- data/test/test_application.rb +13 -9
- data/test/test_cookie.rb +65 -0
- data/test/test_deferrable.rb +7 -7
- data/test/test_deferrable_response.rb +8 -8
- data/test/test_dispatch.rb +125 -0
- metadata +62 -11
- data/lib/fastr/session.rb +0 -5
- data/lib/fastr/session/cookie.rb +0 -0
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'fastr/test/logger'
|
2
|
+
require 'eventmachine'
|
3
|
+
|
4
|
+
module Fastr
|
5
|
+
module Test
|
6
|
+
module Controller
|
7
|
+
def self.included(klass)
|
8
|
+
klass.extend(ClassMethods)
|
9
|
+
set_defaults(klass)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Sets up the test class.
|
13
|
+
def self.set_defaults(klass)
|
14
|
+
regex = Regexp.new(/^(\w+)ControllerTest$/)
|
15
|
+
match = regex.match(klass.to_s)
|
16
|
+
|
17
|
+
if not match.nil?
|
18
|
+
klass.instance_variable_set(:@controller_class, match[1].to_s.uncamelcase)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Runs a test application.
|
23
|
+
#
|
24
|
+
# @param The code to run.
|
25
|
+
def run_test_app(&block)
|
26
|
+
EM.kqueue = true if EM.kqueue?
|
27
|
+
EM.epoll = true if EM.epoll?
|
28
|
+
EM.run do
|
29
|
+
app_path = Dir.pwd
|
30
|
+
app = Fastr::Test::Application.new(app_path)
|
31
|
+
app.boot
|
32
|
+
setup_dumb_router(app)
|
33
|
+
return block.call(app)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Sets up a router that has one route. We will always use / when calling dispatch.
|
38
|
+
def setup_dumb_router(app)
|
39
|
+
app.router.for '/', :to => "dummy#index"
|
40
|
+
end
|
41
|
+
|
42
|
+
def get(action, options={})
|
43
|
+
make_request(:get, action, options)
|
44
|
+
end
|
45
|
+
|
46
|
+
def post(action, options={})
|
47
|
+
make_request(:post, action, options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def make_request(method, action, options={})
|
51
|
+
run_test_app do |app|
|
52
|
+
env = {"PATH_INFO" => "/", "REQUEST_METHOD" => method.to_s.upcase}
|
53
|
+
case method
|
54
|
+
when :get then
|
55
|
+
env['QUERY_STRING'] = Fastr::HTTP.build_query_string(options[:params]) if options[:params]
|
56
|
+
when :post then
|
57
|
+
env['rack.input'] = StringIO.new(Fastr::HTTP.build_query_string(options[:params])) if options[:params]
|
58
|
+
end
|
59
|
+
|
60
|
+
app.route = {:ok => {:controller => get_controller_class, :action => action}}
|
61
|
+
app.dispatch(env)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_controller_class
|
66
|
+
klass = self.class.instance_variable_get(:@controller_class)
|
67
|
+
raise Exception.new("No controller set. Use set_controller.") if klass.nil?
|
68
|
+
return klass
|
69
|
+
end
|
70
|
+
|
71
|
+
module ClassMethods
|
72
|
+
def set_controller(controller)
|
73
|
+
@controller_class = controller.to_s
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
$fastr_settings_loaded = true
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class DispatchController < Fastr::Controller
|
2
|
+
def simple
|
3
|
+
[200, {"Content-Type" => "text/plain"}, ["success"]]
|
4
|
+
end
|
5
|
+
|
6
|
+
def simple_header
|
7
|
+
self.headers['Test-Header'] = 'abc'
|
8
|
+
[200, {}, ["success"]]
|
9
|
+
end
|
10
|
+
|
11
|
+
def render_header
|
12
|
+
self.headers['Test-Header'] = 'abc'
|
13
|
+
render(:text, "success")
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_get_params
|
17
|
+
[200, {}, [get_params, params]]
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_post_params
|
21
|
+
[200, {}, [post_params, params]]
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_controller_params
|
25
|
+
[200, {}, [[params[:controller], params[:action]]]]
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_cookies
|
29
|
+
[200, {}, [cookies]]
|
30
|
+
end
|
31
|
+
end
|
data/test/helper.rb
CHANGED
@@ -21,19 +21,21 @@ end
|
|
21
21
|
|
22
22
|
class ManualBootingApplication < Fastr::Application
|
23
23
|
include Fastr::Log
|
24
|
-
|
24
|
+
|
25
25
|
def initialize(path)
|
26
26
|
self.app_path = path
|
27
27
|
self.plugins = []
|
28
|
+
self.settings = Fastr::Settings.new(self)
|
28
29
|
@booting = true
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
33
|
class Test::Unit::TestCase
|
33
|
-
def em_setup
|
34
|
+
def em_setup(timeout = 0)
|
34
35
|
EM.run do
|
36
|
+
EM.add_timer(timeout) { EM.stop }
|
35
37
|
yield
|
36
|
-
EM.stop
|
38
|
+
EM.stop if timeout == 0
|
37
39
|
end
|
38
40
|
end
|
39
41
|
end
|
@@ -43,4 +45,4 @@ class Fastr::Log::Formatter
|
|
43
45
|
#block all logging output during testing
|
44
46
|
#puts "[#{severity}] [#{self.progname}]: #{msg}"
|
45
47
|
end
|
46
|
-
end
|
48
|
+
end
|
data/test/test_application.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
class TestApplication < Test::Unit::TestCase
|
4
|
-
|
5
|
-
context "New Application" do
|
4
|
+
|
5
|
+
context "New Application" do
|
6
6
|
setup do
|
7
7
|
em_setup{ @application = NueteredBootingApplication.new("/some/path") }
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
should "store startup path" do
|
11
11
|
assert_equal "/some/path",@application.app_path
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
should "boot application" do
|
15
15
|
assert @application.booted
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
context "Application Boot" do
|
20
20
|
setup do
|
21
21
|
em_setup {
|
@@ -23,17 +23,21 @@ class TestApplication < Test::Unit::TestCase
|
|
23
23
|
@application.send(:boot).join
|
24
24
|
}
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
|
+
should "load settings file" do
|
28
|
+
assert($fastr_settings_loaded)
|
29
|
+
end
|
30
|
+
|
27
31
|
should "load app controllers" do
|
28
32
|
assert defined?(FastrAppController)
|
29
33
|
end
|
30
|
-
|
34
|
+
|
31
35
|
should "create router" do
|
32
36
|
assert_not_nil @application.router
|
33
37
|
end
|
34
|
-
|
38
|
+
|
35
39
|
should "setup routes from route file" do
|
36
40
|
assert_equal 3,@application.router.routes.size
|
37
41
|
end
|
38
42
|
end
|
39
|
-
end
|
43
|
+
end
|
data/test/test_cookie.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestCookie < Test::Unit::TestCase
|
4
|
+
include Fastr::Cookie
|
5
|
+
|
6
|
+
attr_accessor :headers
|
7
|
+
|
8
|
+
context "set cookies from controller" do
|
9
|
+
setup do
|
10
|
+
self.headers = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
should "add cookie to array if header exists" do
|
14
|
+
self.headers["Set-Cookie"] = ['dummycookie']
|
15
|
+
set_cookie("key", "value")
|
16
|
+
|
17
|
+
assert_equal(2, self.headers['Set-Cookie'].length)
|
18
|
+
end
|
19
|
+
|
20
|
+
should "put cookie into array if no header exists" do
|
21
|
+
set_cookie("key", "value")
|
22
|
+
|
23
|
+
assert(self.headers['Set-Cookie'].kind_of? Array)
|
24
|
+
assert_equal(1, self.headers['Set-Cookie'].length)
|
25
|
+
end
|
26
|
+
|
27
|
+
should "set cookie key and value" do
|
28
|
+
set_cookie("key", "value")
|
29
|
+
|
30
|
+
hdr = self.headers['Set-Cookie']
|
31
|
+
|
32
|
+
assert_not_nil(hdr)
|
33
|
+
cookie = hdr[0]
|
34
|
+
assert_not_nil(cookie)
|
35
|
+
assert_equal(1, hdr.length)
|
36
|
+
|
37
|
+
assert_equal("key=value;", cookie)
|
38
|
+
end
|
39
|
+
|
40
|
+
should "add options into cookie" do
|
41
|
+
set_cookie("key", "value", {:a => 'b', :c => 'd'})
|
42
|
+
|
43
|
+
hdr = self.headers['Set-Cookie'][0]
|
44
|
+
assert_equal("key=value; a=b; c=d;", hdr)
|
45
|
+
end
|
46
|
+
|
47
|
+
should "add expires to cookie with correct format" do
|
48
|
+
time = Time.utc(2000, 1, 1, 0, 0, 0)
|
49
|
+
|
50
|
+
set_cookie("key", "value", {:expires => time})
|
51
|
+
|
52
|
+
hdr = self.headers['Set-Cookie'][0]
|
53
|
+
assert_equal("key=value; expires=Sat, 01-Jan-2000 00:00:00 GMT;", hdr)
|
54
|
+
end
|
55
|
+
|
56
|
+
should "add expires to cookie in utc if time is local" do
|
57
|
+
time = Time.utc(2000, 1, 1, 0, 0, 0).getlocal
|
58
|
+
|
59
|
+
set_cookie("key", "value", {:expires => time})
|
60
|
+
|
61
|
+
hdr = self.headers['Set-Cookie'][0]
|
62
|
+
assert_equal("key=value; expires=Sat, 01-Jan-2000 00:00:00 GMT;", hdr)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/test/test_deferrable.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
class TestDeferrable < Test::Unit::TestCase
|
4
|
-
|
4
|
+
|
5
5
|
context "Deferrable includer" do
|
6
6
|
setup do
|
7
7
|
@deferrable = DeferrableHost.new
|
@@ -23,11 +23,11 @@ class TestDeferrable < Test::Unit::TestCase
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
should "pass sent data data through to server callback" do
|
28
|
-
assert_not_nil @deferrable.callbacks.index("hey\n")
|
28
|
+
assert_not_nil @deferrable.callbacks.index("hey\n")
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
should "run long task sent through response" do
|
32
32
|
assert_not_nil @deferrable.callbacks.index("processing...\n")
|
33
33
|
end
|
@@ -37,11 +37,11 @@ end
|
|
37
37
|
class DeferrableHost
|
38
38
|
include Fastr::Deferrable
|
39
39
|
attr_accessor :callbacks
|
40
|
-
|
40
|
+
|
41
41
|
def initialize
|
42
42
|
@callbacks = []
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
def env
|
46
46
|
{"async.callback"=>
|
47
47
|
Proc.new{|array|
|
@@ -52,4 +52,4 @@ class DeferrableHost
|
|
52
52
|
}
|
53
53
|
}
|
54
54
|
end
|
55
|
-
end
|
55
|
+
end
|
@@ -1,35 +1,35 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
class TestDeferrableResponse < Test::Unit::TestCase
|
4
|
-
|
4
|
+
|
5
5
|
context "DeferrableResponse" do
|
6
6
|
setup do
|
7
7
|
Fastr::Deferrable
|
8
8
|
@response = Fastr::DeferrableResponse.new
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
should "hold onto callback to push data through to" do
|
12
12
|
@response.each {|data| assert_equal "Some Data",data }
|
13
13
|
@response.send_data("Some Data")
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
should "execute deferred tasks" do
|
17
17
|
Object.expects(:touch!).times(2)
|
18
|
-
em_setup do
|
18
|
+
em_setup(2) do
|
19
19
|
task = proc { Object.touch! }
|
20
20
|
callback = proc { Object.touch! }
|
21
21
|
@response.task(task,callback)
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
should "call success callback when told to finish" do
|
26
26
|
callback_path = nil
|
27
|
-
em_setup do
|
27
|
+
em_setup do
|
28
28
|
@response.callback { callback_path = "success" }
|
29
29
|
@response.errback { callback_path = "failure" }
|
30
|
-
@response.finish
|
30
|
+
@response.finish
|
31
31
|
end
|
32
32
|
assert_equal "success",callback_path
|
33
33
|
end
|
34
34
|
end
|
35
|
-
end
|
35
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'mocha'
|
3
|
+
|
4
|
+
class TestDispatch < Test::Unit::TestCase
|
5
|
+
include Fastr::Dispatch
|
6
|
+
include Fastr::Log
|
7
|
+
|
8
|
+
attr_accessor :plugins, :app
|
9
|
+
|
10
|
+
def method_missing(name, *args)
|
11
|
+
self.app.send(name, *args)
|
12
|
+
end
|
13
|
+
|
14
|
+
context "dispatching a request" do
|
15
|
+
setup do
|
16
|
+
self.plugins = []
|
17
|
+
em_setup do
|
18
|
+
self.app = NueteredBootingApplication.new(APP_PATH)
|
19
|
+
self.app.router = Fastr::Router.new(self.app)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
should "return server not ready if booting" do
|
24
|
+
@booting = true
|
25
|
+
|
26
|
+
code, headers, body = *dispatch({})
|
27
|
+
assert_equal(500, code)
|
28
|
+
assert_equal({'Content-Type' => 'text/plain'}, headers)
|
29
|
+
assert_equal(["Server Not Ready"], body)
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when doing dispatch" do
|
33
|
+
should "return static file if it exists" do
|
34
|
+
env = {"PATH_INFO" => "/static.txt"}
|
35
|
+
code, headers, body = *do_dispatch(env)
|
36
|
+
assert_equal(200, code)
|
37
|
+
assert_equal('text/plain', headers['Content-Type'])
|
38
|
+
assert_equal(['static'], body)
|
39
|
+
end
|
40
|
+
|
41
|
+
should "return 404 if no route exists" do
|
42
|
+
env = {"PATH_INFO" => "/some/invalid/route"}
|
43
|
+
code, headers, body = *do_dispatch(env)
|
44
|
+
assert_equal(404, code)
|
45
|
+
assert_equal('text/plain', headers['Content-Type'])
|
46
|
+
assert_equal(['404 Not Found: /some/invalid/route'], body)
|
47
|
+
end
|
48
|
+
|
49
|
+
context "and routing to a controller" do
|
50
|
+
should "return the response" do
|
51
|
+
env = {"PATH_INFO" => "/"}
|
52
|
+
self.app.router.for '/', :to => "dispatch#simple"
|
53
|
+
response = do_dispatch(env)
|
54
|
+
assert_equal([200, {"Content-Type" => "text/plain"}, ["success"]], response)
|
55
|
+
end
|
56
|
+
|
57
|
+
should "merge the controller's headers into the response" do
|
58
|
+
env = {"PATH_INFO" => "/"}
|
59
|
+
self.app.router.for '/', :to => "dispatch#simple_header"
|
60
|
+
code, headers, body = *do_dispatch(env)
|
61
|
+
assert_equal(200, code)
|
62
|
+
assert_equal('abc', headers['Test-Header'])
|
63
|
+
assert_equal(['success'], body)
|
64
|
+
end
|
65
|
+
|
66
|
+
should "set controller and action params" do
|
67
|
+
env = {"PATH_INFO" => "/"}
|
68
|
+
self.app.router.for '/', :to => "dispatch#test_controller_params"
|
69
|
+
code, headers, body = *do_dispatch(env)
|
70
|
+
assert_equal('dispatch', body[0][0])
|
71
|
+
assert_equal('test_controller_params', body[0][1])
|
72
|
+
end
|
73
|
+
|
74
|
+
should "set get params for a get request" do
|
75
|
+
env = {"PATH_INFO" => "/", "QUERY_STRING" => "a=b&c=d", "REQUEST_METHOD" => "GET"}
|
76
|
+
params = {'a' => 'b', 'c' => 'd'}
|
77
|
+
self.app.router.for '/', :to => "dispatch#test_get_params"
|
78
|
+
code, headers, body = *do_dispatch(env)
|
79
|
+
assert_equal(params, body[0])
|
80
|
+
|
81
|
+
params.each do |k,v|
|
82
|
+
assert(body[1].has_key? k)
|
83
|
+
assert(v, body[1][k])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
should "set post params for a post request" do
|
88
|
+
env = {"PATH_INFO" => "/", "rack.input" => StringIO.new("a=b&c=d"), "REQUEST_METHOD" => "POST"}
|
89
|
+
params = {'a' => 'b', 'c' => 'd'}
|
90
|
+
self.app.router.for '/', :to => "dispatch#test_post_params"
|
91
|
+
code, headers, body = *do_dispatch(env)
|
92
|
+
assert_equal(params, body[0])
|
93
|
+
|
94
|
+
params.each do |k,v|
|
95
|
+
assert(body[1].has_key? k)
|
96
|
+
assert(v, body[1][k])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
should "set cookies" do
|
101
|
+
env = {"PATH_INFO" => "/", "HTTP_COOKIE" => "a = b; c = d;", "REQUEST_METHOD" => "GET"}
|
102
|
+
cookies = {'a' => 'b', 'c' => 'd'}
|
103
|
+
self.app.router.for '/', :to => "dispatch#test_cookies"
|
104
|
+
code, headers, body = *do_dispatch(env)
|
105
|
+
|
106
|
+
cookies.each do |k,v|
|
107
|
+
assert(body[0].has_key? k)
|
108
|
+
assert(v, body[0][k])
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
should "preserve headers if render is called" do
|
113
|
+
env = {"PATH_INFO" => "/"}
|
114
|
+
self.app.router.for '/', :to => "dispatch#render_header"
|
115
|
+
code, headers, body = *do_dispatch(env)
|
116
|
+
assert_equal(200, code)
|
117
|
+
assert_equal('abc', headers['Test-Header'])
|
118
|
+
assert_equal(['success'], body)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
end
|