generic_resource_tests.rb 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. module GenericResourceTests
  2. def test_should_return_all_options
  3. options '/'
  4. assert_response :ok
  5. DAV4RackIntegrationTest::METHODS.each do |method|
  6. assert @response['allow'].include?(method), "headers did not include #{method}"
  7. end
  8. assert_equal '1', @response.headers['Dav']
  9. end
  10. def test_should_render_directory_index
  11. mkcol('/folder')
  12. put('/folder/somefile', :input => 'body')
  13. get '/'
  14. assert_response :ok
  15. assert_match '>folder', @response.body
  16. get '/folder'
  17. assert_response :ok
  18. assert_match '>somefile', @response.body
  19. end
  20. def test_should_propfind_with_depth_zero
  21. propfind '/', env: {'HTTP_DEPTH' => '0'}, input: <<-PROPFIND
  22. <?xml version="1.0" encoding="utf-8"?>
  23. <propfind xmlns="DAV:"><prop>
  24. <getcontentlength xmlns="DAV:"/>
  25. <getlastmodified xmlns="DAV:"/>
  26. <displayname xmlns="DAV:"/>
  27. <resourcetype xmlns="DAV:"/>
  28. <foo xmlns="http://example.com/neon/litmus/"/>
  29. <bar xmlns="http://example.com/neon/litmus/"/>
  30. </prop></propfind>
  31. PROPFIND
  32. assert_response :multi_status
  33. response = response_xml.xpath("//d:response")
  34. assert_equal 1, response.size
  35. response = response.first
  36. assert_equal 2, response.xpath("//d:propstat").size
  37. assert response.xpath("//d:propstat/d:status").detect{|e|e.text =~ /200/}
  38. assert response.xpath("//d:propstat/d:status").detect{|e|e.text =~ /404/}
  39. end
  40. def test_should_return_headers
  41. put '/test.html', input: '<html/>'
  42. assert_response :created
  43. head '/test.html'
  44. assert_response :ok
  45. assert @response.headers['etag']
  46. assert_match(/html/, @response.headers['content-type'])
  47. assert @response.headers['last-modified']
  48. end
  49. def test_should_not_find_a_nonexistent_resource
  50. get '/not_found'
  51. assert_response :not_found
  52. end
  53. def test_should_translate_directory_traversal_to_an_absolute_path
  54. put '/test', input: 'body'
  55. assert_response :created
  56. get '/../../../test'
  57. assert_response :ok
  58. assert_equal 'body', @response.body
  59. end
  60. def test_should_create_a_resource_and_allow_its_retrieval
  61. put '/test.txt', input: 'body'
  62. assert_response :created
  63. get '/test.txt'
  64. assert_response :ok
  65. assert_equal 'body', @response.body
  66. end
  67. def test_should_return_an_absolute_url_after_a_put_request
  68. put '/test', :input => 'body'
  69. assert_response :created
  70. assert_match(/http:\/\/localhost(:\d+)?\/test/, @response['Location'])
  71. end
  72. def test_should_create_and_find_a_url_with_escaped_characters
  73. put '/a b', input: 'body'
  74. assert_response :created
  75. get '/a b'
  76. assert_response :ok
  77. assert_equal 'body', @response.body
  78. end
  79. def test_should_delete_a_single_resource
  80. put '/test', input: 'body'
  81. assert_response :created
  82. delete '/test'
  83. assert_response :no_content
  84. end
  85. def test_should_delete_recursively
  86. mkcol('/folder')
  87. assert_response :created
  88. put('/folder/a', :input => 'body')
  89. assert_response :created
  90. put('/folder/b', :input => 'body')
  91. assert_response :created
  92. delete('/folder')
  93. assert_response :no_content
  94. get('/folder')
  95. assert_response :not_found
  96. get('/folder/a')
  97. assert_response :not_found
  98. get('/folder/b')
  99. assert_response :not_found
  100. end
  101. def test_should_not_allow_copy_to_another_domain
  102. put('/test', :input => 'body')
  103. assert_response :created
  104. copy('/test', env: {'HTTP_DESTINATION' => 'http://another/test'})
  105. assert_response :bad_gateway
  106. end
  107. def test_should_not_allow_copy_to_the_same_resource
  108. put('/test', :input => 'body')
  109. assert_response :created
  110. copy('/test', env: { 'HTTP_DESTINATION' => '/test' })
  111. assert_response :forbidden
  112. end
  113. def test_should_copy_a_single_resource
  114. put '/test', input: 'body'
  115. assert_response :created
  116. copy '/test', env: { 'HTTP_DESTINATION' => '/copy' }
  117. assert_response :created
  118. get '/copy'
  119. assert_response :ok
  120. assert_equal 'body', @response.body
  121. end
  122. def test_should_copy_a_resource_with_escaped_characters
  123. put '/a b', input: 'body'
  124. assert_response :created
  125. copy('/a b', env: { 'HTTP_DESTINATION' => url_escape('/a c') })
  126. assert_response :created
  127. get '/a c'
  128. assert_response :ok
  129. assert_equal 'body', @response.body
  130. end
  131. def test_should_deny_a_copy_without_overwrite
  132. put('/test', :input => 'body')
  133. assert_response :created
  134. put('/copy', :input => 'copy')
  135. assert_response :created
  136. copy('/test', env: { 'HTTP_DESTINATION' => '/copy', 'HTTP_OVERWRITE' => 'F'})
  137. assert_response :precondition_failed
  138. get('/copy')
  139. assert_equal 'copy', @response.body
  140. end
  141. def test_should_allow_a_copy_with_overwrite
  142. put('/test', :input => 'body')
  143. assert_response :created
  144. put('/copy', :input => 'copy')
  145. assert_response :created
  146. copy('/test', env: { 'HTTP_DESTINATION' => '/copy', 'HTTP_OVERWRITE' => 'T'})
  147. assert_response :no_content
  148. get('/copy')
  149. assert_equal 'body', @response.body
  150. end
  151. def test_should_copy_a_collection
  152. mkcol('/folder')
  153. assert_response :created
  154. copy('/folder', env: { 'HTTP_DESTINATION' => '/copy' })
  155. assert_response :created
  156. propfind('/copy', input: propfind_xml(:resourcetype))
  157. refute multistatus_response('/d:propstat/d:prop/d:resourcetype/d:collection').empty?
  158. end
  159. def test_should_copy_a_collection_resursively
  160. mkcol('/folder')
  161. assert_response :created
  162. put('/folder/a', :input => 'A')
  163. assert_response :created
  164. put('/folder/b', :input => 'B')
  165. assert_response :created
  166. copy('/folder', env: { 'HTTP_DESTINATION' => '/copy' })
  167. assert_response :created
  168. propfind('/copy', :input => propfind_xml(:resourcetype))
  169. refute multistatus_response('/d:propstat/d:prop/d:resourcetype/d:collection').empty?
  170. get('/copy/a')
  171. assert_equal 'A', @response.body
  172. get('/copy/b')
  173. assert_equal 'B', @response.body
  174. end
  175. def test_should_move_a_collection_recursively
  176. mkcol('/folder')
  177. assert_response :created
  178. put('/folder/a', :input => 'A')
  179. assert_response :created
  180. put('/folder/b', :input => 'B')
  181. assert_response :created
  182. move('/folder', env: {'HTTP_DESTINATION' => '/move'})
  183. assert_response :created
  184. propfind('/move', input: propfind_xml(:resourcetype))
  185. refute multistatus_response('/d:propstat/d:prop/d:resourcetype/d:collection').empty?
  186. get('/move/a')
  187. assert_equal 'A', @response.body
  188. get('/move/b')
  189. assert_equal 'B', @response.body
  190. get('/folder/a')
  191. assert_response :not_found
  192. get('/folder/b')
  193. assert_response :not_found
  194. end
  195. def test_should_create_a_collection
  196. mkcol('/folder')
  197. assert_response :created
  198. propfind('/folder', :input => propfind_xml(:resourcetype))
  199. refute multistatus_response('/d:propstat/d:prop/d:resourcetype/d:collection').empty?
  200. end
  201. def test_should_return_full_urls_after_creating_a_collection
  202. mkcol('/folder')
  203. assert_response :created
  204. propfind('/folder', :input => propfind_xml(:resourcetype))
  205. refute multistatus_response('/d:propstat/d:prop/d:resourcetype/d:collection').empty?
  206. assert_match(/http:\/\/localhost(:\d+)?\/folder/, multistatus_response('/d:href').first.text)
  207. end
  208. def test_should_not_find_properties_for_nonexistent_resources
  209. propfind('/non')
  210. assert_response :not_found
  211. end
  212. def test_should_find_all_properties
  213. xml = render(:propfind) { |x| x.allprop }
  214. propfind '/', input: xml
  215. assert_match(/http:\/\/localhost(:\d+)?\//,
  216. multistatus_response('/d:href').first.text.strip)
  217. %w(creationdate displayname getlastmodified getetag resourcetype getcontenttype getcontentlength).each do |prop|
  218. refute multistatus_response("/d:propstat/d:prop/d:#{prop}").empty?
  219. end
  220. end
  221. def test_should_find_propnames
  222. xml = render(:propfind) { |x| x.propname }
  223. propfind '/', input: xml
  224. assert_match(/http:\/\/localhost(:\d+)?\//,
  225. multistatus_response('/d:href').first.text.strip)
  226. %w(creationdate displayname getlastmodified getetag resourcetype getcontenttype getcontentlength).each do |prop|
  227. prop_xml = multistatus_response("/d:propstat/d:prop/d:#{prop}").first
  228. assert prop_xml.text.empty?, "expected #{prop_xml} to be empty"
  229. end
  230. end
  231. def test_should_find_named_properties
  232. put '/test.html', input: '<html/>'
  233. assert_response :created
  234. propfind '/test.html',
  235. input: propfind_xml(:getcontenttype, :getcontentlength)
  236. assert_equal 'text/html',
  237. multistatus_response('/d:propstat/d:prop/d:getcontenttype').first.text
  238. assert_equal '7',
  239. multistatus_response('/d:propstat/d:prop/d:getcontentlength').first.text
  240. end
  241. def test_should_lock_a_resource
  242. put '/test', input: 'body'
  243. assert_response :created
  244. xml = render(:lockinfo) do |x|
  245. x.lockscope { x.exclusive }
  246. x.locktype { x.write }
  247. x.owner { x.href "http://test.de/" }
  248. end
  249. lock '/test', input: xml
  250. assert_response :ok
  251. match = ->(pattern){
  252. response_xml.xpath "/d:prop/d:lockdiscovery/d:activelock#{pattern}"
  253. }
  254. refute match[''].empty?
  255. refute match['/d:locktype'].empty?
  256. refute match['/d:lockscope'].empty?
  257. refute match['/d:depth'].empty?
  258. refute match['/d:timeout'].empty?
  259. refute match['/d:locktoken'].empty?
  260. refute match['/d:owner'].empty?
  261. end
  262. def test_should_return_correct_urls_when_not_mapped_to_root
  263. put('/test', input: 'body', env: { 'SCRIPT_NAME' => '/webdav' })
  264. assert_response :created
  265. assert @response.headers['Location'].end_with? '/webdav/test'
  266. end
  267. end