strelka 0.0.1pre4 → 0.0.1.pre129
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/History.rdoc +1 -1
- data/IDEAS.rdoc +62 -0
- data/Manifest.txt +38 -7
- data/README.rdoc +124 -5
- data/Rakefile +22 -6
- data/bin/leash +102 -157
- data/contrib/hoetemplate/.autotest.erb +23 -0
- data/contrib/hoetemplate/History.rdoc.erb +4 -0
- data/contrib/hoetemplate/Manifest.txt.erb +8 -0
- data/contrib/hoetemplate/README.rdoc.erb +17 -0
- data/contrib/hoetemplate/Rakefile.erb +24 -0
- data/contrib/hoetemplate/data/file_name/apps/file_name_app +36 -0
- data/contrib/hoetemplate/data/file_name/templates/layout.tmpl.erb +13 -0
- data/contrib/hoetemplate/data/file_name/templates/top.tmpl.erb +8 -0
- data/contrib/hoetemplate/lib/file_name.rb.erb +18 -0
- data/contrib/hoetemplate/spec/file_name_spec.rb.erb +21 -0
- data/data/strelka/apps/hello-world +30 -0
- data/lib/strelka/app/defaultrouter.rb +49 -30
- data/lib/strelka/app/errors.rb +121 -0
- data/lib/strelka/app/exclusiverouter.rb +40 -0
- data/lib/strelka/app/filters.rb +18 -7
- data/lib/strelka/app/negotiation.rb +122 -0
- data/lib/strelka/app/parameters.rb +171 -14
- data/lib/strelka/app/paramvalidator.rb +751 -0
- data/lib/strelka/app/plugins.rb +66 -46
- data/lib/strelka/app/restresources.rb +499 -0
- data/lib/strelka/app/router.rb +73 -0
- data/lib/strelka/app/routing.rb +140 -18
- data/lib/strelka/app/templating.rb +12 -3
- data/lib/strelka/app.rb +174 -24
- data/lib/strelka/constants.rb +0 -20
- data/lib/strelka/exceptions.rb +29 -0
- data/lib/strelka/httprequest/acceptparams.rb +377 -0
- data/lib/strelka/httprequest/negotiation.rb +257 -0
- data/lib/strelka/httprequest.rb +155 -7
- data/lib/strelka/httpresponse/negotiation.rb +579 -0
- data/lib/strelka/httpresponse.rb +140 -0
- data/lib/strelka/logging.rb +4 -1
- data/lib/strelka/mixins.rb +53 -0
- data/lib/strelka.rb +22 -1
- data/spec/data/error.tmpl +1 -0
- data/spec/lib/constants.rb +0 -1
- data/spec/lib/helpers.rb +21 -0
- data/spec/strelka/app/defaultrouter_spec.rb +41 -35
- data/spec/strelka/app/errors_spec.rb +212 -0
- data/spec/strelka/app/exclusiverouter_spec.rb +220 -0
- data/spec/strelka/app/filters_spec.rb +196 -0
- data/spec/strelka/app/negotiation_spec.rb +73 -0
- data/spec/strelka/app/parameters_spec.rb +149 -0
- data/spec/strelka/app/paramvalidator_spec.rb +1059 -0
- data/spec/strelka/app/plugins_spec.rb +26 -19
- data/spec/strelka/app/restresources_spec.rb +393 -0
- data/spec/strelka/app/router_spec.rb +63 -0
- data/spec/strelka/app/routing_spec.rb +183 -9
- data/spec/strelka/app/templating_spec.rb +1 -2
- data/spec/strelka/app_spec.rb +265 -32
- data/spec/strelka/exceptions_spec.rb +53 -0
- data/spec/strelka/httprequest/acceptparams_spec.rb +282 -0
- data/spec/strelka/httprequest/negotiation_spec.rb +246 -0
- data/spec/strelka/httprequest_spec.rb +204 -14
- data/spec/strelka/httpresponse/negotiation_spec.rb +464 -0
- data/spec/strelka/httpresponse_spec.rb +114 -0
- data/spec/strelka/mixins_spec.rb +99 -0
- data.tar.gz.sig +1 -0
- metadata +175 -79
- metadata.gz.sig +2 -0
- data/IDEAS.textile +0 -174
- data/data/strelka/apps/strelka-admin +0 -65
- data/data/strelka/apps/strelka-setup +0 -26
- data/data/strelka/bootstrap-config.rb +0 -34
- data/data/strelka/templates/admin/console.tmpl +0 -21
- data/data/strelka/templates/layout.tmpl +0 -30
- data/lib/strelka/process.rb +0 -19
@@ -31,6 +31,26 @@ describe Strelka::App::Plugins do
|
|
31
31
|
reset_logging()
|
32
32
|
end
|
33
33
|
|
34
|
+
RSpec::Matchers.define( :order ) do |item|
|
35
|
+
match do |enumerable|
|
36
|
+
if defined?( @before )
|
37
|
+
enumerable.index( @before ) < enumerable.index( item )
|
38
|
+
elsif defined?( @after )
|
39
|
+
enumerable.index( @after ) > enumerable.index( item )
|
40
|
+
else
|
41
|
+
raise "No .before or .after to compare against!"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
chain :before do |item|
|
46
|
+
@before = item
|
47
|
+
end
|
48
|
+
|
49
|
+
chain :after do |item|
|
50
|
+
@after = item
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
34
54
|
|
35
55
|
describe "Plugin module" do
|
36
56
|
|
@@ -63,16 +83,9 @@ describe Strelka::App::Plugins do
|
|
63
83
|
end
|
64
84
|
end
|
65
85
|
|
66
|
-
it "
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
it "knows that it is before the other plugin" do
|
71
|
-
@before_mod.should be_before( @other_mod )
|
72
|
-
end
|
73
|
-
|
74
|
-
it "sorts before the other plugin" do
|
75
|
-
[ @other_mod, @before_mod].sort.should == [ @before_mod, @other_mod ]
|
86
|
+
it "sorts before it in the plugin registry" do
|
87
|
+
Strelka::App.loaded_plugins.tsort.
|
88
|
+
should order( @other_mod.plugin_name ).before( @before_mod.plugin_name )
|
76
89
|
end
|
77
90
|
|
78
91
|
end
|
@@ -88,16 +101,10 @@ describe Strelka::App::Plugins do
|
|
88
101
|
end
|
89
102
|
end
|
90
103
|
|
91
|
-
it "knows that it is after the other plugin" do
|
92
|
-
@after_mod.should be_after( @other_mod )
|
93
|
-
end
|
94
|
-
|
95
|
-
it "knows that is isn't before the other plugin" do
|
96
|
-
@after_mod.should_not be_before( @other_mod )
|
97
|
-
end
|
98
104
|
|
99
|
-
it "sorts after the
|
100
|
-
|
105
|
+
it "sorts after it in the plugin registry" do
|
106
|
+
Strelka::App.loaded_plugins.tsort.
|
107
|
+
should order( @other_mod.plugin_name ).after( @after_mod.plugin_name )
|
101
108
|
end
|
102
109
|
|
103
110
|
end
|
@@ -0,0 +1,393 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
BEGIN {
|
4
|
+
require 'pathname'
|
5
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
|
6
|
+
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
7
|
+
}
|
8
|
+
|
9
|
+
require 'rspec'
|
10
|
+
|
11
|
+
require 'spec/lib/helpers'
|
12
|
+
|
13
|
+
require 'strelka'
|
14
|
+
require 'strelka/app/plugins'
|
15
|
+
require 'strelka/app/restresources'
|
16
|
+
|
17
|
+
require 'strelka/behavior/plugin'
|
18
|
+
require 'mongrel2/config/dsl'
|
19
|
+
|
20
|
+
|
21
|
+
#####################################################################
|
22
|
+
### C O N T E X T S
|
23
|
+
#####################################################################
|
24
|
+
|
25
|
+
describe Strelka::App::RestResources do
|
26
|
+
include Mongrel2::Config::DSL
|
27
|
+
|
28
|
+
before( :all ) do
|
29
|
+
setup_logging( :fatal )
|
30
|
+
setup_config_db()
|
31
|
+
|
32
|
+
@request_factory = Mongrel2::RequestFactory.new( route: '/api/v1' )
|
33
|
+
end
|
34
|
+
|
35
|
+
after( :all ) do
|
36
|
+
reset_logging()
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
it_should_behave_like( "A Strelka::App Plugin" )
|
41
|
+
|
42
|
+
|
43
|
+
describe "an including App" do
|
44
|
+
|
45
|
+
before( :each ) do
|
46
|
+
Strelka.log.debug "Creating a new Strelka::App"
|
47
|
+
@app = Class.new( Strelka::App ) do
|
48
|
+
plugin :restresources
|
49
|
+
def initialize( appid='rest-test', sspec=TEST_SEND_SPEC, rspec=TEST_RECV_SPEC )
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
it "knows what resources are mounted where" do
|
57
|
+
@app.resource_verbs.should be_a( Hash )
|
58
|
+
@app.resource_verbs.should be_empty()
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
describe "with a resource declared using default options" do
|
63
|
+
|
64
|
+
subject { @app }
|
65
|
+
|
66
|
+
before( :each ) do
|
67
|
+
@app.class_eval do
|
68
|
+
resource Mongrel2::Config::Server
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it "knows about the mounted resource" do
|
73
|
+
@app.resource_verbs.should have( 1 ).member
|
74
|
+
@app.resource_verbs.should include( 'servers' )
|
75
|
+
@app.resource_verbs[ 'servers' ].
|
76
|
+
should include( :OPTIONS, :GET, :HEAD, :POST, :PUT, :DELETE )
|
77
|
+
end
|
78
|
+
|
79
|
+
# Reader regular routes
|
80
|
+
it { should have_route(:OPTIONS, 'servers') }
|
81
|
+
it { should have_route(:GET, 'servers') }
|
82
|
+
it { should have_route(:GET, 'servers/:id') }
|
83
|
+
|
84
|
+
# Writer regular routes
|
85
|
+
it { should have_route(:POST, 'servers') }
|
86
|
+
it { should have_route(:PUT, 'servers') }
|
87
|
+
it { should have_route(:PUT, 'servers/:id') }
|
88
|
+
it { should have_route(:DELETE, 'servers') }
|
89
|
+
it { should have_route(:DELETE, 'servers/:id') }
|
90
|
+
|
91
|
+
# Reader composite routes
|
92
|
+
it { should have_route(:GET, 'servers/by_uuid/:uuid') }
|
93
|
+
it { should have_route(:GET, 'servers/:id/hosts') }
|
94
|
+
it { should have_route(:GET, 'servers/:id/filters') }
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
describe "with a resource declared as read-only" do
|
100
|
+
|
101
|
+
subject { @app }
|
102
|
+
|
103
|
+
before( :each ) do
|
104
|
+
@app.class_eval do
|
105
|
+
resource Mongrel2::Config::Server, readonly: true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it "knows about the mounted resource" do
|
110
|
+
@app.resource_verbs.should have( 1 ).member
|
111
|
+
@app.resource_verbs.should include( 'servers' )
|
112
|
+
@app.resource_verbs[ 'servers' ].
|
113
|
+
should include( :OPTIONS, :GET, :HEAD )
|
114
|
+
@app.resource_verbs[ 'servers' ].
|
115
|
+
should_not include( :POST, :PUT, :DELETE )
|
116
|
+
end
|
117
|
+
|
118
|
+
# Reader regular routes
|
119
|
+
it { should have_route(:OPTIONS, 'servers') }
|
120
|
+
it { should have_route(:GET, 'servers') }
|
121
|
+
it { should have_route(:GET, 'servers/:id') }
|
122
|
+
|
123
|
+
# Writer regular routes
|
124
|
+
it { should_not have_route(:POST, 'servers') }
|
125
|
+
it { should_not have_route(:PUT, 'servers') }
|
126
|
+
it { should_not have_route(:PUT, 'servers/:id') }
|
127
|
+
it { should_not have_route(:DELETE, 'servers') }
|
128
|
+
it { should_not have_route(:DELETE, 'servers/:id') }
|
129
|
+
|
130
|
+
# Reader composite routes
|
131
|
+
it { should have_route(:GET, 'servers/by_uuid/:uuid') }
|
132
|
+
it { should have_route(:GET, 'servers/:id/hosts') }
|
133
|
+
it { should have_route(:GET, 'servers/:id/filters') }
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
describe "route behaviors" do
|
139
|
+
|
140
|
+
before( :each ) do
|
141
|
+
# Create two servers in the config db to test with
|
142
|
+
server 'test-server' do
|
143
|
+
host 'main'
|
144
|
+
host 'monitor'
|
145
|
+
host 'adminpanel'
|
146
|
+
host 'api'
|
147
|
+
end
|
148
|
+
server 'step-server'
|
149
|
+
|
150
|
+
@app.class_eval do
|
151
|
+
resource Mongrel2::Config::Server
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
after( :each ) do
|
156
|
+
# Clear the database after each test
|
157
|
+
Mongrel2::Config.subclasses.each {|klass| klass.truncate }
|
158
|
+
end
|
159
|
+
|
160
|
+
context "OPTIONS routes" do
|
161
|
+
it "responds to a top-level OPTIONS request with a resource description (JSON Schema?)"
|
162
|
+
it "responds to an OPTIONS request for a particular resource with details about it" do
|
163
|
+
req = @request_factory.options( '/api/v1/servers' )
|
164
|
+
res = @app.new.handle( req )
|
165
|
+
|
166
|
+
res.status.should == HTTP::OK
|
167
|
+
res.headers.allowed.split( /\s*,\s*/ ).should include(*%w[GET HEAD POST PUT DELETE])
|
168
|
+
end
|
169
|
+
end # OPTIONS routes
|
170
|
+
|
171
|
+
|
172
|
+
context "GET routes" do
|
173
|
+
it "has a GET route to fetch the resource collection" do
|
174
|
+
req = @request_factory.get( '/api/v1/servers', 'Accept' => 'application/json' )
|
175
|
+
res = @app.new.handle( req )
|
176
|
+
|
177
|
+
res.content_type.should == 'application/json'
|
178
|
+
body = Yajl.load( res.body )
|
179
|
+
|
180
|
+
body.should have( 2 ).members
|
181
|
+
body.map {|record| record['uuid'] }.should include( 'test-server', 'step-server' )
|
182
|
+
end
|
183
|
+
|
184
|
+
it "supports limiting the result set when fetching the resource collection" do
|
185
|
+
req = @request_factory.get( '/api/v1/servers?limit=1', 'Accept' => 'application/json' )
|
186
|
+
res = @app.new.handle( req )
|
187
|
+
|
188
|
+
res.status.should == HTTP::OK
|
189
|
+
res.content_type.should == 'application/json'
|
190
|
+
body = Yajl.load( res.body )
|
191
|
+
|
192
|
+
body.should have( 1 ).member
|
193
|
+
body[0]['uuid'].should == 'test-server'
|
194
|
+
end
|
195
|
+
|
196
|
+
it "supports paging the result set when fetching the resource collection" do
|
197
|
+
req = @request_factory.get( '/api/v1/servers?limit=1;offset=1', 'Accept' => 'application/json' )
|
198
|
+
res = @app.new.handle( req )
|
199
|
+
|
200
|
+
res.status.should == HTTP::OK
|
201
|
+
res.content_type.should == 'application/json'
|
202
|
+
body = Yajl.load( res.body )
|
203
|
+
|
204
|
+
body.should have( 1 ).member
|
205
|
+
body[0]['uuid'].should == 'step-server'
|
206
|
+
end
|
207
|
+
|
208
|
+
it "has a GET route to fetch a single resource by its ID" do
|
209
|
+
req = @request_factory.get( '/api/v1/servers/1', 'Accept' => 'application/json' )
|
210
|
+
res = @app.new.handle( req )
|
211
|
+
|
212
|
+
res.content_type.should == 'application/json'
|
213
|
+
body = Yajl.load( res.body )
|
214
|
+
|
215
|
+
body.should be_a( Hash )
|
216
|
+
body['uuid'].should == 'test-server'
|
217
|
+
end
|
218
|
+
|
219
|
+
it "returns a NOT FOUND response when fetching a non-existant resource" do
|
220
|
+
req = @request_factory.get( '/api/v1/servers/411', 'Accept' => 'application/json' )
|
221
|
+
res = @app.new.handle( req )
|
222
|
+
|
223
|
+
res.status.should == HTTP::NOT_FOUND
|
224
|
+
res.body.should =~ /no such server/i
|
225
|
+
end
|
226
|
+
|
227
|
+
it "returns a NOT FOUND response when fetching a resource with an invalid ID" do
|
228
|
+
req = @request_factory.get( '/api/v1/servers/ape-tastic' )
|
229
|
+
res = @app.new.handle( req )
|
230
|
+
|
231
|
+
res.status.should == HTTP::NOT_FOUND
|
232
|
+
res.body.should =~ /requested resource was not found/i
|
233
|
+
end
|
234
|
+
|
235
|
+
it "has a GET route for fetching the resource via one of its dataset methods" do
|
236
|
+
req = @request_factory.get( '/api/v1/servers/by_uuid/test-server', :accept => 'application/json' )
|
237
|
+
res = @app.new.handle( req )
|
238
|
+
|
239
|
+
res.status.should == HTTP::OK
|
240
|
+
body = Yajl.load( res.body )
|
241
|
+
|
242
|
+
body.should be_an( Array )
|
243
|
+
body.should have( 1 ).member
|
244
|
+
body.first.should be_a( Hash )
|
245
|
+
body.first['uuid'].should == 'test-server'
|
246
|
+
end
|
247
|
+
|
248
|
+
it "has a GET route for fetching the resource's associated objects" do
|
249
|
+
req = @request_factory.get( '/api/v1/servers/1/hosts' )
|
250
|
+
res = @app.new.handle( req )
|
251
|
+
|
252
|
+
res.status.should == HTTP::OK
|
253
|
+
body = Yajl.load( res.body )
|
254
|
+
|
255
|
+
body.should be_an( Array )
|
256
|
+
body.should have( 4 ).members
|
257
|
+
body.first.should be_a( Hash )
|
258
|
+
body.first['server_id'].should == 1
|
259
|
+
body.first['id'].should == 1
|
260
|
+
end
|
261
|
+
|
262
|
+
it "supports offset and limits for composite GET routes" do
|
263
|
+
req = @request_factory.get( '/api/v1/servers/1/hosts?offset=2;limit=2' )
|
264
|
+
res = @app.new.handle( req )
|
265
|
+
|
266
|
+
res.status.should == HTTP::OK
|
267
|
+
body = Yajl.load( res.body )
|
268
|
+
|
269
|
+
body.should be_an( Array )
|
270
|
+
body.should have( 2 ).members
|
271
|
+
body.first.should be_a( Hash )
|
272
|
+
body.first['server_id'].should == 1
|
273
|
+
body.first['id'].should == 3
|
274
|
+
end
|
275
|
+
|
276
|
+
end # GET routes
|
277
|
+
|
278
|
+
|
279
|
+
context "POST routes" do
|
280
|
+
|
281
|
+
before( :each ) do
|
282
|
+
@server_values = {
|
283
|
+
'uuid' => "test-server",
|
284
|
+
'access_log' => "/logs/admin-access.log",
|
285
|
+
'error_log' => "/logs/admin-error.log",
|
286
|
+
'chroot' => "/var/www",
|
287
|
+
'pid_file' => "/var/run/test.pid",
|
288
|
+
'default_host' => "localhost",
|
289
|
+
'name' => "Testing Server",
|
290
|
+
'bind_addr' => "127.0.0.1",
|
291
|
+
'port' => '7337',
|
292
|
+
'use_ssl' => '0',
|
293
|
+
}
|
294
|
+
@host_values = {
|
295
|
+
'name' => 'step',
|
296
|
+
'matching' => 'step.example.com',
|
297
|
+
}
|
298
|
+
end
|
299
|
+
|
300
|
+
it "has a POST route to create instances in the resource collection" do
|
301
|
+
req = @request_factory.post( '/api/v1/servers' )
|
302
|
+
req.content_type = 'application/json'
|
303
|
+
req.body = Yajl.dump( @server_values )
|
304
|
+
|
305
|
+
res = @app.new.handle( req )
|
306
|
+
|
307
|
+
res.status.should == HTTP::CREATED
|
308
|
+
res.headers.location.should == 'http://localhost:8080/api/v1/servers/3'
|
309
|
+
|
310
|
+
new_server = Mongrel2::Config::Server[ 3 ]
|
311
|
+
|
312
|
+
new_server.uuid.should == "test-server"
|
313
|
+
new_server.access_log.should == "/logs/admin-access.log"
|
314
|
+
new_server.error_log.should == "/logs/admin-error.log"
|
315
|
+
new_server.chroot.should == "/var/www"
|
316
|
+
new_server.pid_file.should == "/var/run/test.pid"
|
317
|
+
new_server.default_host.should == "localhost"
|
318
|
+
new_server.name.should == "Testing Server"
|
319
|
+
new_server.bind_addr.should == "127.0.0.1"
|
320
|
+
new_server.port.should == 7337
|
321
|
+
new_server.use_ssl.should == 0
|
322
|
+
end
|
323
|
+
|
324
|
+
end # POST routes
|
325
|
+
|
326
|
+
|
327
|
+
context "PUT routes" do
|
328
|
+
|
329
|
+
before( :each ) do
|
330
|
+
@posted_values = {
|
331
|
+
'name' => 'Not A Testing Server',
|
332
|
+
'bind_addr' => '0.0.0.0',
|
333
|
+
}
|
334
|
+
end
|
335
|
+
|
336
|
+
it "has a PUT route to update instances in the resource collection" do
|
337
|
+
req = @request_factory.put( '/api/v1/servers/1' )
|
338
|
+
req.content_type = 'application/json'
|
339
|
+
req.headers.accept = 'application/json'
|
340
|
+
req.body = Yajl.dump( @posted_values )
|
341
|
+
|
342
|
+
res = @app.new.handle( req )
|
343
|
+
|
344
|
+
res.status.should == HTTP::NO_CONTENT
|
345
|
+
|
346
|
+
Mongrel2::Config::Server[ 1 ].name.should == 'Not A Testing Server'
|
347
|
+
Mongrel2::Config::Server[ 1 ].bind_addr.should == '0.0.0.0'
|
348
|
+
end
|
349
|
+
|
350
|
+
it "has a PUT route to mass-update all resources in a collection" do
|
351
|
+
req = @request_factory.put( '/api/v1/servers' )
|
352
|
+
req.content_type = 'application/json'
|
353
|
+
req.body = Yajl.dump({ 'bind_addr' => '0.0.0.0' })
|
354
|
+
|
355
|
+
res = @app.new.handle( req )
|
356
|
+
|
357
|
+
res.status.should == HTTP::NO_CONTENT
|
358
|
+
|
359
|
+
Mongrel2::Config::Server.map( :bind_addr ).uniq.should == ['0.0.0.0']
|
360
|
+
end
|
361
|
+
|
362
|
+
end # PUT routes
|
363
|
+
|
364
|
+
|
365
|
+
context "DELETE routes" do
|
366
|
+
|
367
|
+
it "has a DELETE route to delete single instances in the resource collection" do
|
368
|
+
req = @request_factory.delete( '/api/v1/servers/1' )
|
369
|
+
|
370
|
+
res = @app.new.handle( req )
|
371
|
+
|
372
|
+
res.status.should == HTTP::NO_CONTENT
|
373
|
+
|
374
|
+
Mongrel2::Config::Server.count.should == 1
|
375
|
+
end
|
376
|
+
|
377
|
+
it "has a DELETE route to mass-delete all resources in a collection" do
|
378
|
+
req = @request_factory.delete( '/api/v1/servers' )
|
379
|
+
|
380
|
+
res = @app.new.handle( req )
|
381
|
+
|
382
|
+
res.status.should == HTTP::NO_CONTENT
|
383
|
+
|
384
|
+
Mongrel2::Config::Server.count.should == 0
|
385
|
+
end
|
386
|
+
|
387
|
+
end # DELETE routes
|
388
|
+
|
389
|
+
end # route behaviors
|
390
|
+
|
391
|
+
end
|
392
|
+
|
393
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
BEGIN {
|
4
|
+
require 'pathname'
|
5
|
+
basedir = Pathname.new( __FILE__ ).dirname.parent.parent.parent
|
6
|
+
$LOAD_PATH.unshift( basedir ) unless $LOAD_PATH.include?( basedir )
|
7
|
+
}
|
8
|
+
|
9
|
+
require 'rspec'
|
10
|
+
|
11
|
+
require 'spec/lib/helpers'
|
12
|
+
|
13
|
+
require 'strelka'
|
14
|
+
require 'strelka/app/router'
|
15
|
+
|
16
|
+
|
17
|
+
#####################################################################
|
18
|
+
### C O N T E X T S
|
19
|
+
#####################################################################
|
20
|
+
|
21
|
+
describe Strelka::App::Router do
|
22
|
+
|
23
|
+
before( :all ) do
|
24
|
+
setup_logging( :fatal )
|
25
|
+
@request_factory = Mongrel2::RequestFactory.new( route: '/user' )
|
26
|
+
end
|
27
|
+
|
28
|
+
after( :all ) do
|
29
|
+
reset_logging()
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
it "looks for plugins under strelka/app" do
|
34
|
+
Strelka::App::Router.derivative_dirs.should include( 'strelka/app' )
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
it "is abstract" do
|
39
|
+
expect {
|
40
|
+
Strelka::App::Router.new
|
41
|
+
}.to raise_error()
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
describe "concrete subclasses" do
|
46
|
+
|
47
|
+
subject { Class.new(described_class).new }
|
48
|
+
|
49
|
+
it "raises NotImplementedErrors if they don't implement #add_route" do
|
50
|
+
expect {
|
51
|
+
subject.add_route(:GET, '', lambda {})
|
52
|
+
}.to raise_error(NotImplementedError)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "raises NotImplementedErrors if they don't implement #route_request" do
|
56
|
+
expect {
|
57
|
+
subject.route_request(:request)
|
58
|
+
}.to raise_error(NotImplementedError)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|