lotus-controller 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,175 @@
1
+ require 'test_helper'
2
+ require 'lotus/router'
3
+
4
+ MimeRoutes = Lotus::Router.new do
5
+ get '/', to: 'mimes#default'
6
+ get '/custom', to: 'mimes#custom'
7
+ get '/accept', to: 'mimes#accept'
8
+ get '/restricted', to: 'mimes#restricted'
9
+ end
10
+
11
+ class MimesController
12
+ include Lotus::Controller
13
+
14
+ action 'Default' do
15
+ def call(params)
16
+ end
17
+ end
18
+
19
+ action 'Custom' do
20
+ def call(params)
21
+ self.content_type = 'application/xml'
22
+ end
23
+ end
24
+
25
+ action 'Accept' do
26
+ def call(params)
27
+ self.headers.merge!({'X-AcceptDefault' => accept?('application/octet-stream').to_s })
28
+ self.headers.merge!({'X-AcceptHtml' => accept?('text/html').to_s })
29
+ self.headers.merge!({'X-AcceptXml' => accept?('application/xml').to_s })
30
+ self.headers.merge!({'X-AcceptJson' => accept?('text/json').to_s })
31
+ end
32
+ end
33
+
34
+ action 'Restricted' do
35
+ accept :html, :json
36
+
37
+ def call(params)
38
+ end
39
+ end
40
+ end
41
+
42
+ describe 'Content type' do
43
+ before do
44
+ @app = Rack::MockRequest.new(MimeRoutes)
45
+ end
46
+
47
+ it 'fallbacks to the default "Content-Type" header when the request is lacking of this information' do
48
+ response = @app.get('/')
49
+ response.headers['Content-Type'].must_equal 'application/octet-stream'
50
+ end
51
+
52
+ it 'returns the specified "Content-Type" header' do
53
+ response = @app.get('/custom')
54
+ response.headers['Content-Type'].must_equal 'application/xml'
55
+ end
56
+
57
+ describe 'when Accept is sent' do
58
+ it 'sets "Content-Type" header according to "Accept"' do
59
+ response = @app.get('/', 'HTTP_ACCEPT' => '*/*')
60
+ response.headers['Content-Type'].must_equal 'application/octet-stream'
61
+ end
62
+
63
+ it 'sets "Content-Type" header according to "Accept"' do
64
+ response = @app.get('/', 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')
65
+ response.headers['Content-Type'].must_equal 'text/html'
66
+ end
67
+
68
+ it 'sets "Content-Type" header according to "Accept" quality scale' do
69
+ response = @app.get('/', 'HTTP_ACCEPT' => 'application/json;q=0.6,application/xml;q=0.9,*/*;q=0.8')
70
+ response.headers['Content-Type'].must_equal 'application/xml'
71
+ end
72
+ end
73
+ end
74
+
75
+ describe 'Accept' do
76
+ before do
77
+ @app = Rack::MockRequest.new(MimeRoutes)
78
+ @response = @app.get('/accept', 'HTTP_ACCEPT' => accept)
79
+ end
80
+
81
+ describe 'when Accept is missing' do
82
+ let(:accept) { nil }
83
+
84
+ it 'accepts all' do
85
+ @response.headers['X-AcceptDefault'].must_equal 'true'
86
+ @response.headers['X-AcceptHtml'].must_equal 'true'
87
+ @response.headers['X-AcceptXml'].must_equal 'true'
88
+ @response.headers['X-AcceptJson'].must_equal 'true'
89
+ end
90
+ end
91
+
92
+ describe 'when Accept is sent' do
93
+ describe 'when "*/*"' do
94
+ let(:accept) { '*/*' }
95
+
96
+ it 'accepts all' do
97
+ @response.headers['X-AcceptDefault'].must_equal 'true'
98
+ @response.headers['X-AcceptHtml'].must_equal 'true'
99
+ @response.headers['X-AcceptXml'].must_equal 'true'
100
+ @response.headers['X-AcceptJson'].must_equal 'true'
101
+ end
102
+ end
103
+
104
+ describe 'when "text/html"' do
105
+ let(:accept) { 'text/html' }
106
+
107
+ it 'accepts selected mime types' do
108
+ @response.headers['X-AcceptDefault'].must_equal 'false'
109
+ @response.headers['X-AcceptHtml'].must_equal 'true'
110
+ @response.headers['X-AcceptXml'].must_equal 'false'
111
+ @response.headers['X-AcceptJson'].must_equal 'false'
112
+ end
113
+ end
114
+
115
+ describe 'when weighted' do
116
+ let(:accept) { 'text/html,application/xhtml+xml,application/xml;q=0.9' }
117
+
118
+ it 'accepts selected mime types' do
119
+ @response.headers['X-AcceptDefault'].must_equal 'false'
120
+ @response.headers['X-AcceptHtml'].must_equal 'true'
121
+ @response.headers['X-AcceptXml'].must_equal 'true'
122
+ @response.headers['X-AcceptJson'].must_equal 'false'
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ describe 'Restricted Accept' do
129
+ before do
130
+ @app = Rack::MockRequest.new(MimeRoutes)
131
+ @response = @app.get('/restricted', 'HTTP_ACCEPT' => accept)
132
+ end
133
+
134
+ describe 'when Accept is missing' do
135
+ let(:accept) { nil }
136
+
137
+ it 'returns the mime type according to the application defined policy' do
138
+ @response.status.must_equal 200
139
+ end
140
+ end
141
+
142
+ describe 'when Accept is sent' do
143
+ describe 'when "*/*"' do
144
+ let(:accept) { '*/*' }
145
+
146
+ it 'returns the mime type according to the application defined policy' do
147
+ @response.status.must_equal 200
148
+ end
149
+ end
150
+
151
+ describe 'when accepted' do
152
+ let(:accept) { 'text/html' }
153
+
154
+ it 'accepts selected mime types' do
155
+ @response.status.must_equal 200
156
+ end
157
+ end
158
+
159
+ describe 'when not accepted' do
160
+ let(:accept) { 'application/xml' }
161
+
162
+ it 'accepts selected mime types' do
163
+ @response.status.must_equal 406
164
+ end
165
+ end
166
+
167
+ describe 'when weighted' do
168
+ let(:accept) { 'text/html,application/xhtml+xml,application/xml;q=0.9' }
169
+
170
+ it 'accepts selected mime types' do
171
+ @response.status.must_equal 200
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,141 @@
1
+ require 'test_helper'
2
+ require 'lotus/router'
3
+
4
+ Routes = Lotus::Router.new do
5
+ get '/', to: 'root'
6
+ get '/team', to: 'about#team'
7
+ get '/contacts', to: 'about#contacts'
8
+
9
+ resource :identity
10
+ resources :flowers
11
+ end
12
+
13
+ describe 'Lotus::Router integration' do
14
+ before do
15
+ @app = Rack::MockRequest.new(Routes)
16
+ end
17
+
18
+ it 'calls simple action' do
19
+ response = @app.get('/')
20
+
21
+ response.status.must_equal 200
22
+ response.body.must_equal '{}'
23
+ response.headers['X-Test'].must_equal 'test'
24
+ end
25
+
26
+ it "calls a controller's class action" do
27
+ response = @app.get('/team')
28
+
29
+ response.status.must_equal 200
30
+ response.body.must_equal '{}'
31
+ response.headers['X-Test'].must_equal 'test'
32
+ end
33
+
34
+ it "calls a controller's action (with DSL)" do
35
+ response = @app.get('/contacts')
36
+
37
+ response.status.must_equal 200
38
+ response.body.must_equal '{}'
39
+ end
40
+
41
+ it 'returns a 404 for unknown path' do
42
+ response = @app.get('/unknown')
43
+
44
+ response.status.must_equal 404
45
+ end
46
+
47
+ describe 'resource' do
48
+ it 'calls GET show' do
49
+ response = @app.get('/identity')
50
+
51
+ response.status.must_equal 200
52
+ response.body.must_equal "{}"
53
+ end
54
+
55
+ it 'calls GET new' do
56
+ response = @app.get('/identity/new')
57
+
58
+ response.status.must_equal 200
59
+ response.body.must_equal '{}'
60
+ end
61
+
62
+ it 'calls POST create' do
63
+ response = @app.post('/identity', params: { identity: { avatar: { image: 'jodosha.png' } }})
64
+
65
+ response.status.must_equal 200
66
+ response.body.must_equal "{:identity=>{:avatar=>{:image=>\"jodosha.png\"}}}"
67
+ end
68
+
69
+ it 'calls GET edit' do
70
+ response = @app.get('/identity/edit')
71
+
72
+ response.status.must_equal 200
73
+ response.body.must_equal "{}"
74
+ end
75
+
76
+ it 'calls PATCH update' do
77
+ response = @app.request('PATCH', '/identity', params: { identity: { avatar: { image: 'jodosha-2x.png' } }})
78
+
79
+ response.status.must_equal 200
80
+ response.body.must_equal "{:identity=>{:avatar=>{:image=>\"jodosha-2x.png\"}}}"
81
+ end
82
+
83
+ it 'calls DELETE destroy' do
84
+ response = @app.delete('/identity')
85
+
86
+ response.status.must_equal 200
87
+ response.body.must_equal "{}"
88
+ end
89
+ end
90
+
91
+ describe 'resources' do
92
+ it 'calls GET index' do
93
+ response = @app.get('/flowers')
94
+
95
+ response.status.must_equal 200
96
+ response.body.must_equal '{}'
97
+ end
98
+
99
+ it 'calls GET show' do
100
+ response = @app.get('/flowers/23')
101
+
102
+ response.status.must_equal 200
103
+ response.body.must_equal "{:id=>\"23\"}"
104
+ end
105
+
106
+ it 'calls GET new' do
107
+ response = @app.get('/flowers/new')
108
+
109
+ response.status.must_equal 200
110
+ response.body.must_equal '{}'
111
+ end
112
+
113
+ it 'calls POST create' do
114
+ response = @app.post('/flowers', params: { flower: { name: 'Lotus' } })
115
+
116
+ response.status.must_equal 200
117
+ response.body.must_equal "{:flower=>{:name=>\"Lotus\"}}"
118
+ end
119
+
120
+ it 'calls GET edit' do
121
+ response = @app.get('/flowers/23/edit')
122
+
123
+ response.status.must_equal 200
124
+ response.body.must_equal "{:id=>\"23\"}"
125
+ end
126
+
127
+ it 'calls PATCH update' do
128
+ response = @app.request('PATCH', '/flowers/23', params: { flower: { name: 'Lotus!' } })
129
+
130
+ response.status.must_equal 200
131
+ response.body.must_equal "{:flower=>{:name=>\"Lotus!\"}, :id=>\"23\"}"
132
+ end
133
+
134
+ it 'calls DELETE destroy' do
135
+ response = @app.delete('/flowers/23')
136
+
137
+ response.status.must_equal 200
138
+ response.body.must_equal "{:id=>\"23\"}"
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,63 @@
1
+ require 'test_helper'
2
+ require 'rack/test'
3
+ require 'lotus/router'
4
+
5
+ SessionRoutes = Lotus::Router.new do
6
+ get '/', to: 'dashboard#index'
7
+ post '/login', to: 'sessions#create'
8
+ delete '/logout', to: 'sessions#destroy'
9
+ end
10
+
11
+ SessionApplication = Rack::Builder.new do
12
+ use Rack::Session::Cookie, secret: SecureRandom.hex(16)
13
+ run SessionRoutes
14
+ end.to_app
15
+
16
+ StandaloneSessionApplication = Rack::Builder.new do
17
+ use Rack::Session::Cookie, secret: SecureRandom.hex(16)
18
+ run StandaloneSession.new
19
+ end
20
+
21
+ describe 'Sessions' do
22
+ include Rack::Test::Methods
23
+
24
+ def app
25
+ SessionApplication
26
+ end
27
+
28
+ it "denies access if user isn't loggedin" do
29
+ get '/'
30
+ last_response.status.must_equal 401
31
+ end
32
+
33
+ it 'grant access after login' do
34
+ post '/login'
35
+ follow_redirect!
36
+ last_response.status.must_equal 200
37
+ end
38
+
39
+ it 'logs out' do
40
+ post '/login'
41
+ follow_redirect!
42
+ last_response.status.must_equal 200
43
+
44
+ delete '/logout'
45
+
46
+ get '/'
47
+ last_response.status.must_equal 401
48
+ end
49
+ end
50
+
51
+ describe 'Standalone Sessions' do
52
+ include Rack::Test::Methods
53
+
54
+ def app
55
+ StandaloneSessionApplication
56
+ end
57
+
58
+ it 'sets the session value' do
59
+ get '/'
60
+ last_response.status.must_equal 200
61
+ last_response.headers.fetch('Set-Cookie').must_match(/\Arack\.session/)
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ describe Lotus::Action do
4
+ describe 'redirect' do
5
+ it 'redirects to the given path' do
6
+ action = RedirectAction.new
7
+ response = action.call({})
8
+
9
+ response[0].must_equal(302)
10
+ response[1].must_equal({ 'Content-Type' => 'application/octet-stream', 'Location' => '/destination' })
11
+ end
12
+
13
+ it 'redirects with custom status code' do
14
+ action = StatusRedirectAction.new
15
+ response = action.call({})
16
+
17
+ response[0].must_equal(301)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+
3
+ describe Lotus::Action do
4
+ describe 'session' do
5
+ it 'captures session from Rack env' do
6
+ action = SessionAction.new
7
+ action.call({'rack.session' => session = { 'user_id' => '23' }})
8
+
9
+ action.send(:session).must_equal(session)
10
+ end
11
+
12
+ it 'returns empty hash when it is missing' do
13
+ action = SessionAction.new
14
+ action.call({})
15
+
16
+ action.send(:session).must_equal({})
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ if ENV['COVERAGE'] == 'true'
5
+ require 'simplecov'
6
+ require 'coveralls'
7
+
8
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
9
+ SimpleCov::Formatter::HTMLFormatter,
10
+ Coveralls::SimpleCov::Formatter
11
+ ]
12
+
13
+ SimpleCov.start do
14
+ command_name 'test'
15
+ add_filter 'test'
16
+ end
17
+ end
18
+
19
+ require 'minitest/autorun'
20
+ $:.unshift 'lib'
21
+ require 'lotus/controller'
22
+ require 'lotus/action/cookies'
23
+ require 'lotus/action/session'
24
+ require 'fixtures'