mirror of
https://github.com/9001/copyparty.git
synced 2026-09-24 19:50:25 +01:00
support copying files/folders; closes #115
behaves according to the target volume's deduplication config; will create symlinks / hardlinks instead if dedup is enabled
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
# coding: utf-8
|
||||
from __future__ import print_function, unicode_literals
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
from itertools import product
|
||||
|
||||
from copyparty.authsrv import AuthSrv
|
||||
from copyparty.httpcli import HttpCli
|
||||
from tests import util as tu
|
||||
from tests.util import Cfg
|
||||
|
||||
|
||||
class TestDedup(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.td = tu.get_ramdisk()
|
||||
|
||||
def tearDown(self):
|
||||
os.chdir(tempfile.gettempdir())
|
||||
shutil.rmtree(self.td)
|
||||
|
||||
def reset(self):
|
||||
td = os.path.join(self.td, "vfs")
|
||||
if os.path.exists(td):
|
||||
shutil.rmtree(td)
|
||||
os.mkdir(td)
|
||||
os.chdir(td)
|
||||
for a in "abc":
|
||||
os.mkdir(a)
|
||||
for b in "fg":
|
||||
d = "%s/%s%s" % (a, a, b)
|
||||
os.mkdir(d)
|
||||
for fn in "x":
|
||||
fp = "%s/%s%s%s" % (d, a, b, fn)
|
||||
with open(fp, "wb") as f:
|
||||
f.write(fp.encode("utf-8"))
|
||||
return td
|
||||
|
||||
def cinit(self):
|
||||
if self.conn:
|
||||
self.fstab = self.conn.hsrv.hub.up2k.fstab
|
||||
self.conn.hsrv.hub.up2k.shutdown()
|
||||
self.asrv = AuthSrv(self.args, self.log)
|
||||
self.conn = tu.VHttpConn(self.args, self.asrv, self.log, b"", True)
|
||||
if self.fstab:
|
||||
self.conn.hsrv.hub.up2k.fstab = self.fstab
|
||||
|
||||
def test(self):
|
||||
tc_dedup = ["sym", "no"]
|
||||
vols = [".::A", "a/af:a/af:r", "b:a/b:r"]
|
||||
tcs = [
|
||||
"/a?copy=/c/a /a/af/afx /a/ag/agx /a/b/bf/bfx /a/b/bg/bgx /b/bf/bfx /b/bg/bgx /c/a/af/afx /c/a/ag/agx /c/a/b/bf/bfx /c/a/b/bg/bgx /c/cf/cfx /c/cg/cgx",
|
||||
"/b?copy=/d /a/af/afx /a/ag/agx /a/b/bf/bfx /a/b/bg/bgx /b/bf/bfx /b/bg/bgx /c/cf/cfx /c/cg/cgx /d/bf/bfx /d/bg/bgx",
|
||||
"/b/bf?copy=/d /a/af/afx /a/ag/agx /a/b/bf/bfx /a/b/bg/bgx /b/bf/bfx /b/bg/bgx /c/cf/cfx /c/cg/cgx /d/bfx",
|
||||
"/a/af?copy=/d /a/af/afx /a/ag/agx /a/b/bf/bfx /a/b/bg/bgx /b/bf/bfx /b/bg/bgx /c/cf/cfx /c/cg/cgx /d/afx",
|
||||
"/a/af?copy=/ /a/af/afx /a/ag/agx /a/b/bf/bfx /a/b/bg/bgx /afx /b/bf/bfx /b/bg/bgx /c/cf/cfx /c/cg/cgx",
|
||||
"/a/af/afx?copy=/afx /a/af/afx /a/ag/agx /a/b/bf/bfx /a/b/bg/bgx /afx /b/bf/bfx /b/bg/bgx /c/cf/cfx /c/cg/cgx",
|
||||
]
|
||||
|
||||
self.conn = None
|
||||
self.fstab = None
|
||||
self.ctr = 0 # 2304
|
||||
for dedup, act_exp in product(tc_dedup, tcs):
|
||||
action, expect = act_exp.split(" ", 1)
|
||||
t = "dedup:%s action:%s" % (dedup, action)
|
||||
print("\n\n\033[0;7m# ", t, "\033[0m")
|
||||
|
||||
ka = {"dav_inf": True}
|
||||
if dedup == "hard":
|
||||
ka["hardlink"] = True
|
||||
elif dedup == "no":
|
||||
ka["no_dedup"] = True
|
||||
|
||||
self.args = Cfg(v=vols, a=[], **ka)
|
||||
self.reset()
|
||||
self.cinit()
|
||||
|
||||
self.do_cp(action)
|
||||
zs = self.propfind()
|
||||
|
||||
fns = " ".join(zs[1])
|
||||
self.assertEqual(expect, fns)
|
||||
|
||||
def do_cp(self, action):
|
||||
hdr = "POST %s HTTP/1.1\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"
|
||||
buf = (hdr % (action,)).encode("utf-8")
|
||||
print("CP [%s]" % (action,))
|
||||
HttpCli(self.conn.setbuf(buf)).run()
|
||||
ret = self.conn.s._reply.decode("utf-8").split("\r\n\r\n", 1)
|
||||
print("CP <-- ", ret)
|
||||
self.assertIn(" 201 Created", ret[0])
|
||||
self.assertEqual("k\r\n", ret[1])
|
||||
return ret
|
||||
|
||||
def propfind(self):
|
||||
h = "PROPFIND / HTTP/1.1\r\nConnection: close\r\n\r\n"
|
||||
HttpCli(self.conn.setbuf(h.encode("utf-8"))).run()
|
||||
h, t = self.conn.s._reply.decode("utf-8").split("\r\n\r\n", 1)
|
||||
fns = t.split("<D:response><D:href>")[1:]
|
||||
fns = [x.split("</D", 1)[0] for x in fns]
|
||||
fns = [x for x in fns if not x.endswith("/")]
|
||||
fns.sort()
|
||||
return h, fns
|
||||
|
||||
def log(self, src, msg, c=0):
|
||||
print(msg)
|
||||
+2
-2
@@ -122,7 +122,7 @@ class Cfg(Namespace):
|
||||
def __init__(self, a=None, v=None, c=None, **ka0):
|
||||
ka = {}
|
||||
|
||||
ex = "chpw daw dav_auth dav_inf dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink ih ihead magic hardlink_only nid nih no_acode no_athumb no_clone no_dav no_db_ip no_del no_dirsz no_dupe no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tarcmp no_thumb no_vthumb no_zip nrand nw og og_no_head og_s_title ohead q rand re_dirsz rss smb srch_dbg stats uqe vague_403 vc ver write_uplog xdev xlink xvol zs"
|
||||
ex = "chpw daw dav_auth dav_inf dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink ih ihead magic hardlink_only nid nih no_acode no_athumb no_clone no_cp no_dav no_db_ip no_del no_dirsz no_dupe no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tarcmp no_thumb no_vthumb no_zip nrand nw og og_no_head og_s_title ohead q rand re_dirsz rss smb srch_dbg stats uqe vague_403 vc ver write_uplog xdev xlink xvol zs"
|
||||
ka.update(**{k: False for k in ex.split()})
|
||||
|
||||
ex = "dedup dotpart dotsrch hook_v no_dhash no_fastboot no_fpool no_htp no_rescan no_sendfile no_ses no_snap no_up_list no_voldump re_dhash plain_ip"
|
||||
@@ -146,7 +146,7 @@ class Cfg(Namespace):
|
||||
ex = "ban_403 ban_404 ban_422 ban_pw ban_url"
|
||||
ka.update(**{k: "no" for k in ex.split()})
|
||||
|
||||
ex = "grp on403 on404 xad xar xau xban xbd xbr xbu xiu xm"
|
||||
ex = "grp on403 on404 xac xad xar xau xban xbc xbd xbr xbu xiu xm"
|
||||
ka.update(**{k: [] for k in ex.split()})
|
||||
|
||||
ex = "exp_lg exp_md"
|
||||
|
||||
Reference in New Issue
Block a user