fastr 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|