From 1ff12aeb6f939525282c372b59b7e74ae4735f28 Mon Sep 17 00:00:00 2001 From: "COLA@Redmine.local" Date: Sat, 11 Feb 2017 23:32:11 +0100 Subject: [PATCH 1/3] Implemented WebDav PROPFIND test. --- test/fixtures/dmsf_file_revisions.yml | 22 +++ .../webdav/dmsf_webdav_propfind_test.rb | 163 ++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 test/integration/webdav/dmsf_webdav_propfind_test.rb diff --git a/test/fixtures/dmsf_file_revisions.yml b/test/fixtures/dmsf_file_revisions.yml index 4157f9d1..c0f0dc1f 100644 --- a/test/fixtures/dmsf_file_revisions.yml +++ b/test/fixtures/dmsf_file_revisions.yml @@ -143,6 +143,26 @@ dmsf_file_revisions_007: dmsf_file_revisions_008: id: 8 + dmsf_file_id: 9 + source_dmsf_file_revision_id: NULL + name: "myfile.txt" + disk_filename: "myfile.txt" + size: 0 + mime_type: text/plain + title: "My File" + description: NULL + workflow: NULL + minor_version: 0 + major_version: 1 + comment: NULL + deleted: 0 + deleted_by_user_id: NULL + user_id: 1 + dmsf_workflow_assigned_by: NULL + dmsf_workflow_started_by: NULL + +dmsf_file_revisions_009: + id: 9 dmsf_file_id: 10 source_dmsf_file_revision_id: NULL name: "zero.txt" @@ -160,3 +180,5 @@ dmsf_file_revisions_008: user_id: 1 dmsf_workflow_assigned_by: NULL dmsf_workflow_started_by: NULL + + diff --git a/test/integration/webdav/dmsf_webdav_propfind_test.rb b/test/integration/webdav/dmsf_webdav_propfind_test.rb new file mode 100644 index 00000000..e5735567 --- /dev/null +++ b/test/integration/webdav/dmsf_webdav_propfind_test.rb @@ -0,0 +1,163 @@ +# encoding: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# Copyright (C) 2012 Daniel Munn +# Copyright (C) 2011-17 Karel Picman +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../test_helper', __FILE__) + +class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest + + fixtures :projects, :users, :email_addresses, :members, :member_roles, :roles, + :enabled_modules, :dmsf_folders, :dmsf_files, :dmsf_file_revisions + + def setup + @admin = credentials 'admin' + @jsmith = credentials 'jsmith' # Not a member of project1 + @project1 = Project.find_by_id 1 # DMSF enabled + @project2 = Project.find_by_id 2 # DMSF disabled + + # Folders in project1/ + @folder1 = DmsfFolder.find_by_id 1 + @folder6 = DmsfFolder.find_by_id 6 + # Files in project1/ + @file5 = DmsfFile.find_by_id 5 + @file9 = DmsfFile.find_by_id 9 + @file10 = DmsfFile.find_by_id 10 + + Setting.plugin_redmine_dmsf['dmsf_webdav'] = '1' + Setting.plugin_redmine_dmsf['dmsf_webdav_strategy'] = 'WEBDAV_READ_WRITE' + end + + def test_truth + assert_kind_of Project, @project1 + assert_kind_of Project, @project2 + end + + def test_propfind_denied_for_anonymous + xml_http_request :propfind, "/dmsf/webdav/", nil, + {:HTTP_DEPTH => "0"} + assert_response 401 +# puts "\nPROPFIND response.body:\n#{response.body}" unless response.body.nil? + end + + def test_propfind_depth0_on_root_for_non_member + xml_http_request :propfind, "/dmsf/webdav/", nil, + @jsmith.merge!({:HTTP_DEPTH => "0"}) + + assert_response 207 # MultiStatus + assert_match "http://www.example.com:80/dmsf/webdav/", response.body + assert_match "/", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", response.body + assert_no_match "#{@project1.identifier}", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project2.identifier}/", response.body + assert_no_match "#{@project2.identifier}", response.body + end + + def test_propfind_depth1_on_root_for_non_member + xml_http_request :propfind, "/dmsf/webdav/", nil, + @jsmith.merge!({:HTTP_DEPTH => "1"}) + + assert_response 207 # MultiStatus + assert_match "http://www.example.com:80/dmsf/webdav/", response.body + assert_match "/", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", response.body + assert_no_match "#{@project1.identifier}", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project2.identifier}/", response.body + assert_no_match "#{@project2.identifier}", response.body + end + + def test_propfind_depth0_on_root_for_admin + xml_http_request :propfind, "/dmsf/webdav/", nil, + @admin.merge!({:HTTP_DEPTH => "0"}) + + assert_response 207 # MultiStatus + assert_match "http://www.example.com:80/dmsf/webdav/", response.body + assert_match "/", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", response.body + assert_no_match "#{@project1.identifier}", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project2.identifier}/", response.body + assert_no_match "#{@project2.identifier}", response.body + end + + def test_propfind_depth1_on_root_for_admin + xml_http_request :propfind, "/dmsf/webdav/", nil, + @admin.merge!({:HTTP_DEPTH => "1"}) + + assert_response 207 # MultiStatus + assert_match "http://www.example.com:80/dmsf/webdav/", response.body + assert_match "/", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", response.body + assert_match "#{@project1.identifier}", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project2.identifier}/", response.body + assert_no_match "#{@project2.identifier}", response.body + end + + def test_propfind_depth0_on_project1_for_non_member + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @jsmith.merge!({:HTTP_DEPTH => "0"}) + assert_response 404 + end + + def test_propfind_depth0_on_project1_for_admin + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => "0"}) + assert_response 207 # MultiStatus + assert_no_match "http://www.example.com:80/dmsf/webdav/", response.body + assert_no_match "/", response.body + # Project + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", response.body + assert_match "#{@project1.identifier}", response.body + # Folders + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}/", response.body + assert_no_match "#{@folder1.title}", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}/", response.body + assert_no_match "#{@folder6.title}", response.body + # Files + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file5.name}", response.body + assert_no_match "#{@file5.name}", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file9.name}", response.body + assert_no_match "#{@file9.name}", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file10.name}", response.body + assert_no_match "#{@file10.name}", response.body + end + + def test_propfind_depth1_on_project1_for_admin + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => "1"}) + assert_response 207 # MultiStatus + assert_no_match "http://www.example.com:80/dmsf/webdav/", response.body + assert_no_match "/", response.body + # Project + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", response.body + assert_match "#{@project1.identifier}", response.body + # Folders + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}/", response.body + assert_match "#{@folder1.title}", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}/", response.body + assert_match "#{@folder6.title}", response.body + # Files + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file5.name}", response.body + assert_match "#{@file5.name}", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file9.name}", response.body + assert_match "#{@file9.name}", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file10.name}", response.body + assert_match "#{@file10.name}", response.body + end + +end \ No newline at end of file From 54bf8b50541c30353ad3fb9bf7e5401b12b2c799 Mon Sep 17 00:00:00 2001 From: "COLA@Redmine.local" Date: Sun, 12 Feb 2017 02:01:36 +0100 Subject: [PATCH 2/3] resource.path begins with a / so there is no need to add one. --- lib/redmine_dmsf/webdav/controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/redmine_dmsf/webdav/controller.rb b/lib/redmine_dmsf/webdav/controller.rb index d89fb697..4a003e31 100644 --- a/lib/redmine_dmsf/webdav/controller.rb +++ b/lib/redmine_dmsf/webdav/controller.rb @@ -215,7 +215,7 @@ module RedmineDmsf # path is unique enough for the key and is available for all three, and the path doesn't change # for this path as long as it stays. On its path. The path does not stray from its path without # changing its path. - propstats_key = "PROPSTATS/#{resource.path}" + propstats_key = "PROPSTATS#{resource.path}" else # File # Use file.id & file.last_revision.id as key From 1b5f8dfb96b6ef1523b91bea1a035075fe836a0b Mon Sep 17 00:00:00 2001 From: "COLA@Redmine.local" Date: Sun, 12 Feb 2017 02:02:38 +0100 Subject: [PATCH 3/3] Implemented WebDav PROPFIND cache test. --- .../webdav/dmsf_webdav_propfind_test.rb | 91 ++++++++++++++++++- 1 file changed, 86 insertions(+), 5 deletions(-) diff --git a/test/integration/webdav/dmsf_webdav_propfind_test.rb b/test/integration/webdav/dmsf_webdav_propfind_test.rb index e5735567..ef997ada 100644 --- a/test/integration/webdav/dmsf_webdav_propfind_test.rb +++ b/test/integration/webdav/dmsf_webdav_propfind_test.rb @@ -36,7 +36,7 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest @folder1 = DmsfFolder.find_by_id 1 @folder6 = DmsfFolder.find_by_id 6 # Files in project1/ - @file5 = DmsfFile.find_by_id 5 + @file1 = DmsfFile.find_by_id 1 @file9 = DmsfFile.find_by_id 9 @file10 = DmsfFile.find_by_id 10 @@ -129,8 +129,8 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}/", response.body assert_no_match "#{@folder6.title}", response.body # Files - assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file5.name}", response.body - assert_no_match "#{@file5.name}", response.body + assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", response.body + assert_no_match "#{@file1.name}", response.body assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file9.name}", response.body assert_no_match "#{@file9.name}", response.body assert_no_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file10.name}", response.body @@ -152,12 +152,93 @@ class DmsfWebdavPropfindTest < RedmineDmsf::Test::IntegrationTest assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}/", response.body assert_match "#{@folder6.title}", response.body # Files - assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file5.name}", response.body - assert_match "#{@file5.name}", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", response.body + assert_match "#{@file1.name}", response.body assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file9.name}", response.body assert_match "#{@file9.name}", response.body assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file10.name}", response.body assert_match "#{@file10.name}", response.body end + def test_propfind_depth0_on_project1_for_admin_with_cache + RedmineDmsf::Webdav::Cache.init_testcache + + assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +1 do + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => "0"}) + assert_response 207 # MultiStatus + end + + # Response should be correct + # Project + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", response.body + # A new PROPSTATS entry should have been created for project1 + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", RedmineDmsf::Webdav::Cache.read("PROPSTATS/#{@project1.identifier}") + + # Replace the PROPSTATS cache entry and make sure that it is used + RedmineDmsf::Webdav::Cache.write("PROPSTATS/#{@project1.identifier}", "Cached PROPSTATS/#{@project1.identifier}") + + assert_no_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count' do + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => "0"}) + assert_response 207 # MultiStatus + end + assert_match "Cached PROPSTATS/#{@project1.identifier}", response.body + + RedmineDmsf::Webdav::Cache.init_nullcache + end + + def test_propfind_depth1_on_project1_for_admin_with_cache + RedmineDmsf::Webdav::Cache.init_testcache + + assert_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count', +7 do + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => "1"}) + assert_response 207 # MultiStatus + end + + # Project, a new PROPFIND and PROPSTATS should have been created for project1 + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", RedmineDmsf::Webdav::Cache.read("PROPFIND/#{@project1.id}") + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/", RedmineDmsf::Webdav::Cache.read("PROPSTATS/#{@project1.identifier}") + # Folders, new PROPSTATS should be created for each folder. + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}/", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@folder1.title}/", RedmineDmsf::Webdav::Cache.read("PROPSTATS/#{@project1.identifier}/#{@folder1.title}") + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}/", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@folder6.title}/", RedmineDmsf::Webdav::Cache.read("PROPSTATS/#{@project1.identifier}/#{@folder6.title}") + # Files, new PROPSTATS should be created for each folder. + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file1.name}", RedmineDmsf::Webdav::Cache.read("PROPSTATS/#{@file1.id}-#{@file1.last_revision.id}") + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file9.name}", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file9.name}", RedmineDmsf::Webdav::Cache.read("PROPSTATS/#{@file9.id}-#{@file9.last_revision.id}") + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file10.name}", response.body + assert_match "http://www.example.com:80/dmsf/webdav/#{@project1.identifier}/#{@file10.name}", RedmineDmsf::Webdav::Cache.read("PROPSTATS/#{@file10.id}-#{@file10.last_revision.id}") + + # Replace PROPFIND and verify that cached entry is used. + RedmineDmsf::Webdav::Cache.write("PROPFIND/#{@project1.id}", "Cached PROPFIND/#{@project1.id}") + assert_no_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count' do + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => "1"}) + assert_response 207 # MultiStatus + assert_match "Cached PROPFIND/#{@project1.id}", response.body + end + + # Delete PROPFIND, replace PROPSTATS for one entry and verify that it is used when creating the response and new cache + RedmineDmsf::Webdav::Cache.invalidate_item("PROPFIND/#{@project1.id}") + assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}") + assert RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") + RedmineDmsf::Webdav::Cache.write("PROPSTATS/#{@project1.identifier}", "Cached PROPSTATS/#{@project1.identifier}") + # One PROPFIND entry is added and one .invalid entry is deleted, so no differenct. + assert_no_difference 'RedmineDmsf::Webdav::Cache.cache.instance_variable_get(:@data).count' do + xml_http_request :propfind, "/dmsf/webdav/#{@project1.identifier}", nil, + @admin.merge!({:HTTP_DEPTH => "1"}) + assert_response 207 # MultiStatus + end + assert_match "Cached PROPSTATS/#{@project1.identifier}", response.body + assert_match "Cached PROPSTATS/#{@project1.identifier}", RedmineDmsf::Webdav::Cache.read("PROPFIND/#{@project1.id}") + assert !RedmineDmsf::Webdav::Cache.exist?("PROPFIND/#{@project1.id}.invalid") + + RedmineDmsf::Webdav::Cache.init_nullcache + end + end \ No newline at end of file