spec/controller_spec.rb in rack_dav-0.4.0 vs spec/controller_spec.rb in rack_dav-0.4.1
- old
+ new
@@ -24,10 +24,16 @@
map { |k,v| [k.downcase, v] }.flatten]
end
end
+if ENV['TRAVIS']
+ RSpec.configure do |c|
+ c.filter_run_excluding :has_xattr_support => true
+ end
+end
+
describe RackDAV::Handler do
DOC_ROOT = File.expand_path(File.dirname(__FILE__) + '/htdocs')
METHODS = %w(GET PUT POST DELETE PROPFIND PROPPATCH MKCOL COPY MOVE OPTIONS HEAD LOCK UNLOCK)
CLASS_2 = METHODS
@@ -64,11 +70,11 @@
end
end
describe "LOCK" do
before(:each) do
- put("/test", :input => "body").should be_ok
+ put("/test", :input => "body").should be_created
lock("/test", :input => File.read(fixture("requests/lock.xml")))
end
describe "creation" do
it "succeeds" do
@@ -76,11 +82,11 @@
end
it "sets a compliant rack response" do
body = response.original_response.body
body.should be_a(Array)
- body.should have(1).part
+ expect(body.size).to eq(1)
end
it "prints the lockdiscovery" do
lockdiscovery_response response_locktoken
end
@@ -126,11 +132,11 @@
end
end
describe "UNLOCK" do
before(:each) do
- put("/test", :input => "body").should be_ok
+ put("/test", :input => "body").should be_created
lock("/test", :input => File.read(fixture("requests/lock.xml"))).should be_ok
end
context "given a valid token" do
before(:each) do
@@ -174,16 +180,16 @@
)
end
describe "uri escaping" do
it "allows url escaped utf-8" do
- put('/D%C3%B6ner').should be_ok
+ put('/D%C3%B6ner').should be_created
get('/D%C3%B6ner').should be_ok
end
it "allows url escaped iso-8859" do
- put('/D%F6ner').should be_ok
+ put('/D%F6ner').should be_created
get('/D%F6ner').should be_ok
end
end
describe "OPTIONS" do
@@ -220,22 +226,22 @@
put('/foo', :input => 'bar',
'HTTP_CONTENT_MD5' => 'N7UdGUp1E+RbVvZSTy1R8g==')
end
it 'should be successful' do
- response.should be_ok
+ response.should be_created
end
it 'should create the resource' do
get('/foo').should be_ok
response.body.should == 'bar'
end
end
end
it 'should return headers' do
- put('/test.html', :input => '<html/>').should be_ok
+ put('/test.html', :input => '<html/>').should be_created
head('/test.html').should be_ok
response.headers['etag'].should_not be_nil
response.headers['content-type'].should match(/html/)
response.headers['last-modified'].should_not be_nil
@@ -249,93 +255,100 @@
it 'should not allow directory traversal' do
get('/../htdocs').should be_forbidden
end
it 'should create a resource and allow its retrieval' do
- put('/test', :input => 'body').should be_ok
+ put('/test', :input => 'body').should be_created
get('/test').should be_ok
response.body.should == 'body'
end
it 'should create and find a url with escaped characters' do
- put(url_escape('/a b'), :input => 'body').should be_ok
+ put(url_escape('/a b'), :input => 'body').should be_created
get(url_escape('/a b')).should be_ok
response.body.should == 'body'
end
it 'should delete a single resource' do
- put('/test', :input => 'body').should be_ok
+ put('/test', :input => 'body').should be_created
delete('/test').should be_no_content
end
it 'should delete recursively' do
mkcol('/folder').should be_created
- put('/folder/a', :input => 'body').should be_ok
- put('/folder/b', :input => 'body').should be_ok
+ put('/folder/a', :input => 'body').should be_created
+ put('/folder/b', :input => 'body').should be_created
delete('/folder').should be_no_content
get('/folder').should be_not_found
get('/folder/a').should be_not_found
get('/folder/b').should be_not_found
end
+ it 'should return not found when deleting a non-existent resource' do
+ delete('/not_found').should be_not_found
+ end
+
it 'should not allow copy to another domain' do
- put('/test', :input => 'body').should be_ok
+ put('/test', :input => 'body').should be_created
copy('http://localhost/', 'HTTP_DESTINATION' => 'http://another/').should be_bad_gateway
end
it 'should not allow copy to the same resource' do
- put('/test', :input => 'body').should be_ok
+ put('/test', :input => 'body').should be_created
copy('/test', 'HTTP_DESTINATION' => '/test').should be_forbidden
end
it 'should not allow an invalid destination uri' do
- put('/test', :input => 'body').should be_ok
+ put('/test', :input => 'body').should be_created
copy('/test', 'HTTP_DESTINATION' => '%').should be_bad_request
end
it 'should copy a single resource' do
- put('/test', :input => 'body').should be_ok
+ put('/test', :input => 'body').should be_created
copy('/test', 'HTTP_DESTINATION' => '/copy').should be_created
get('/copy').body.should == 'body'
end
it 'should copy a resource with escaped characters' do
- put(url_escape('/a b'), :input => 'body').should be_ok
+ put(url_escape('/a b'), :input => 'body').should be_created
copy(url_escape('/a b'), 'HTTP_DESTINATION' => url_escape('/a c')).should be_created
get(url_escape('/a c')).should be_ok
response.body.should == 'body'
end
it 'should deny a copy without overwrite' do
- put('/test', :input => 'body').should be_ok
- put('/copy', :input => 'copy').should be_ok
- copy('/test', 'HTTP_DESTINATION' => '/copy', 'HTTP_OVERWRITE' => 'F')
+ put('/test', :input => 'body').should be_created
+ put('/copy', :input => 'copy').should be_created
+ copy('/test', 'HTTP_DESTINATION' => '/copy', 'HTTP_OVERWRITE' => 'F').should be_precondition_failed
- multistatus_response('/d:href').first.text.should == 'http://localhost/test'
- multistatus_response('/d:status').first.text.should match(/412 Precondition Failed/)
-
get('/copy').body.should == 'copy'
end
it 'should allow a copy with overwrite' do
- put('/test', :input => 'body').should be_ok
- put('/copy', :input => 'copy').should be_ok
+ put('/test', :input => 'body').should be_created
+ put('/copy', :input => 'copy').should be_created
copy('/test', 'HTTP_DESTINATION' => '/copy', 'HTTP_OVERWRITE' => 'T').should be_no_content
get('/copy').body.should == 'body'
end
+ it 'should deny a move to an existing resource without overwrite' do
+ put('/test', :input => 'body').should be_created
+ put('/copy', :input => 'copy').should be_created
+ move('/test', 'HTTP_DESTINATION' => '/copy', 'HTTP_OVERWRITE' => 'F').should be_precondition_failed
+ end
+
it 'should copy a collection' do
mkcol('/folder').should be_created
copy('/folder', 'HTTP_DESTINATION' => '/copy').should be_created
propfind('/copy', :input => propfind_xml(:resourcetype))
multistatus_response('/d:propstat/d:prop/d:resourcetype/d:collection').should_not be_empty
end
it 'should copy a collection resursively' do
mkcol('/folder').should be_created
- put('/folder/a', :input => 'A').should be_ok
- put('/folder/b', :input => 'B').should be_ok
+ put('/folder/a', :input => 'A').should be_created
+ put('/folder/b', :input => 'B').should be_created
copy('/folder', 'HTTP_DESTINATION' => '/copy').should be_created
propfind('/copy', :input => propfind_xml(:resourcetype))
multistatus_response('/d:propstat/d:prop/d:resourcetype/d:collection').should_not be_empty
@@ -343,12 +356,12 @@
get('/copy/b').body.should == 'B'
end
it 'should move a collection recursively' do
mkcol('/folder').should be_created
- put('/folder/a', :input => 'A').should be_ok
- put('/folder/b', :input => 'B').should be_ok
+ put('/folder/a', :input => 'A').should be_created
+ put('/folder/b', :input => 'B').should be_created
move('/folder', 'HTTP_DESTINATION' => '/move').should be_created
propfind('/move', :input => propfind_xml(:resourcetype))
multistatus_response('/d:propstat/d:prop/d:resourcetype/d:collection').should_not be_empty
@@ -356,23 +369,34 @@
get('/move/b').body.should == 'B'
get('/folder/a').should be_not_found
get('/folder/b').should be_not_found
end
+ it 'should not move a collection onto an existing collection without overwrite' do
+ mkcol('/folder').should be_created
+ mkcol('/dest').should be_created
+
+ move('/folder', 'HTTP_DESTINATION' => '/dest', 'HTTP_OVERWRITE' => 'F').should be_precondition_failed
+ end
+
it 'should create a collection' do
mkcol('/folder').should be_created
propfind('/folder', :input => propfind_xml(:resourcetype))
multistatus_response('/d:propstat/d:prop/d:resourcetype/d:collection').should_not be_empty
end
+ it 'should not create a collection with a body' do
+ mkcol('/folder', :input => 'body').should be_unsupported_media_type
+ end
+
it 'should not find properties for nonexistent resources' do
propfind('/non').should be_not_found
end
it 'should find all properties' do
xml = render do |xml|
- xml.propfind('xmlns:d' => "DAV:") do
+ xml.propfind('xmlns' => "DAV:") do
xml.allprop
end
end
propfind('http://localhost/', :input => xml)
@@ -384,27 +408,65 @@
multistatus_response('/d:propstat/d:prop/d:' + prop).should_not be_empty
end
end
it 'should find named properties' do
- put('/test.html', :input => '<html/>').should be_ok
+ put('/test.html', :input => '<html/>').should be_created
propfind('/test.html', :input => propfind_xml(:getcontenttype, :getcontentlength))
multistatus_response('/d:propstat/d:prop/d:getcontenttype').first.text.should == 'text/html'
multistatus_response('/d:propstat/d:prop/d:getcontentlength').first.text.should == '7'
end
+ it 'should set custom properties in the dav namespace', :has_xattr_support => true do
+ put('/prop', :input => 'A').should be_created
+ proppatch('/prop', :input => propset_xml([:foo, 'testing']))
+ multistatus_response('/d:propstat/d:prop/d:foo').should_not be_empty
+
+ propfind('/prop', :input => propfind_xml(:foo))
+ multistatus_response('/d:propstat/d:prop/d:foo').first.text.should == 'testing'
+ end
+
+ it 'should set custom properties in custom namespaces', :has_xattr_support => true do
+ xmlns = { 'xmlns:s' => 'SPEC:' }
+ put('/prop', :input => 'A').should be_created
+ proppatch('/prop', :input => propset_xml(['s:foo'.to_sym, 'testing', xmlns]))
+ multistatus_response('/d:propstat/d:prop/s:foo', xmlns).should_not be_empty
+
+ propfind('/prop', :input => propfind_xml(['s:foo'.to_sym, xmlns]))
+ multistatus_response('/d:propstat/d:prop/s:foo', xmlns).first.text.should == 'testing'
+ end
+
+ it 'should copy custom properties', :has_xattr_support => true do
+ xmlns = { 'xmlns:s' => 'SPEC:' }
+ put('/prop', :input => 'A').should be_created
+ proppatch('/prop', :input => propset_xml(['s:foo'.to_sym, 'testing', xmlns]))
+ multistatus_response('/d:propstat/d:prop/s:foo', xmlns).should_not be_empty
+
+ copy('/prop', 'HTTP_DESTINATION' => '/propcopy').should be_created
+ propfind('/propcopy', :input => propfind_xml(['s:foo'.to_sym, xmlns]))
+ multistatus_response('/d:propstat/d:prop/s:foo', xmlns).first.text.should == 'testing'
+ end
+
+ it 'should not set properties for a non-existent resource' do
+ proppatch('/not_found', :input => propset_xml([:foo, 'testing'])).should be_not_found
+ end
+
+ it 'should not return properties for non-existent resource' do
+ propfind('/prop', :input => propfind_xml(:foo)).should be_not_found
+ end
+
it 'should return the correct charset (utf-8)' do
- put('/test.html', :input => '<html/>').should be_ok
+ put('/test.html', :input => '<html/>').should be_created
propfind('/test.html', :input => propfind_xml(:getcontenttype, :getcontentlength))
charset = @response.media_type_params['charset']
charset.should eql 'utf-8'
end
it 'should not support LOCK' do
- put('/test', :input => 'body').should be_ok
+ put('/test', :input => 'body').should be_created
xml = render do |xml|
xml.lockinfo('xmlns:d' => "DAV:") do
xml.lockscope { xml.exclusive }
xml.locktype { xml.write }
@@ -414,11 +476,11 @@
lock('/test', :input => xml).should be_method_not_allowed
end
it 'should not support UNLOCK' do
- put('/test', :input => 'body').should be_ok
+ put('/test', :input => 'body').should be_created
unlock('/test', :input => '').should be_method_not_allowed
end
end
@@ -475,24 +537,41 @@
match['/d:timeout'].should_not be_empty
match['/d:locktoken/d:href'].should_not be_empty
match['/d:locktoken/d:href'].first.text.should == token
end
- def multistatus_response(pattern)
+ def multistatus_response(pattern, ns=nil)
+ xmlns = { 'd' => 'DAV:' }
+ xmlns.merge!(ns) unless ns.nil?
+
@response.should be_multi_status
- response_xml.xpath("/d:multistatus/d:response", 'd' => 'DAV:').should_not be_empty
- response_xml.xpath("/d:multistatus/d:response" + pattern, 'd' => 'DAV:')
+ response_xml.xpath("/d:multistatus/d:response", xmlns).should_not be_empty
+ response_xml.xpath("/d:multistatus/d:response" + pattern, xmlns)
end
def propfind_xml(*props)
render do |xml|
- xml.propfind('xmlns:d' => "DAV:") do
+ xml.propfind('xmlns' => "DAV:") do
xml.prop do
- props.each do |prop|
- xml.send prop.to_sym
+ props.each do |prop, attrs|
+ xml.send(prop.to_sym, attrs)
end
end
end
end
end
+ def propset_xml(*props)
+ render do |xml|
+ xml.propertyupdate('xmlns' => 'DAV:') do
+ xml.set do
+ xml.prop do
+ props.each do |prop, value, attrs|
+ attrs = {} if attrs.nil?
+ xml.send(prop.to_sym, value, attrs)
+ end
+ end
+ end
+ end
+ end
+ end
end