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