pytest: add ftp upload tests

- refs #13556
- allow anon uploads on vsftpd test server
- add test_30_05 for plain upload of 1k, 100k, 1m
- add test_31_05 for SSL upload of 1k, 100k, 1m
- verify file size and contents

Closes #13734
This commit is contained in:
Stefan Eissing 2024-05-21 12:17:33 +02:00 committed by Daniel Stenberg
parent f867942511
commit 5a913d8dc3
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
4 changed files with 102 additions and 5 deletions

View file

@ -67,6 +67,9 @@ class TestVsFTPD:
self._make_docs_file(docs_dir=vsftpd.docs_dir, fname='data-10k', fsize=10*1024)
self._make_docs_file(docs_dir=vsftpd.docs_dir, fname='data-1m', fsize=1024*1024)
self._make_docs_file(docs_dir=vsftpd.docs_dir, fname='data-10m', fsize=10*1024*1024)
env.make_data_file(indir=env.gen_dir, fname="upload-1k", fsize=1024)
env.make_data_file(indir=env.gen_dir, fname="upload-100k", fsize=100*1024)
env.make_data_file(indir=env.gen_dir, fname="upload-1m", fsize=1024*1024)
def test_30_01_list_dir(self, env: Env, vsftpd: VsFTPD, repeat):
curl = CurlClient(env=env)
@ -115,6 +118,24 @@ class TestVsFTPD:
r.check_stats(count=count, http_status=226)
self.check_downloads(curl, srcfile, count)
@pytest.mark.parametrize("docname", [
'upload-1k', 'upload-100k', 'upload-1m'
])
def test_30_05_upload_1(self, env: Env, vsftpd: VsFTPD, docname, repeat):
curl = CurlClient(env=env)
srcfile = os.path.join(env.gen_dir, docname)
dstfile = os.path.join(vsftpd.docs_dir, docname)
self._rmf(dstfile)
count = 1
url = f'ftp://{env.ftp_domain}:{vsftpd.port}/'
r = curl.ftp_upload(urls=[url], fupload=f'{srcfile}', with_stats=True)
r.check_stats(count=count, http_status=226)
self.check_upload(env, vsftpd, docname=docname)
def _rmf(self, path):
if os.path.exists(path):
return os.remove(path)
def check_downloads(self, client, srcfile: str, count: int,
complete: bool = True):
for i in range(count):
@ -128,5 +149,15 @@ class TestVsFTPD:
n=1))
assert False, f'download {dfile} differs:\n{diff}'
def check_upload(self, env, vsftpd: VsFTPD, docname):
srcfile = os.path.join(env.gen_dir, docname)
dstfile = os.path.join(vsftpd.docs_dir, docname)
assert os.path.exists(srcfile)
assert os.path.exists(dstfile)
if not filecmp.cmp(srcfile, dstfile, shallow=False):
diff = "".join(difflib.unified_diff(a=open(srcfile).readlines(),
b=open(dstfile).readlines(),
fromfile=srcfile,
tofile=dstfile,
n=1))
assert False, f'upload {dstfile} differs:\n{diff}'

View file

@ -77,6 +77,9 @@ class TestVsFTPD:
self._make_docs_file(docs_dir=vsftpds.docs_dir, fname='data-10k', fsize=10*1024)
self._make_docs_file(docs_dir=vsftpds.docs_dir, fname='data-1m', fsize=1024*1024)
self._make_docs_file(docs_dir=vsftpds.docs_dir, fname='data-10m', fsize=10*1024*1024)
env.make_data_file(indir=env.gen_dir, fname="upload-1k", fsize=1024)
env.make_data_file(indir=env.gen_dir, fname="upload-100k", fsize=100*1024)
env.make_data_file(indir=env.gen_dir, fname="upload-1m", fsize=1024*1024)
def test_31_01_list_dir(self, env: Env, vsftpds: VsFTPD, repeat):
curl = CurlClient(env=env)
@ -125,6 +128,24 @@ class TestVsFTPD:
r.check_stats(count=count, http_status=226)
self.check_downloads(curl, srcfile, count)
@pytest.mark.parametrize("docname", [
'upload-1k', 'upload-100k', 'upload-1m'
])
def test_31_05_upload_1(self, env: Env, vsftpds: VsFTPD, docname, repeat):
curl = CurlClient(env=env)
srcfile = os.path.join(env.gen_dir, docname)
dstfile = os.path.join(vsftpds.docs_dir, docname)
self._rmf(dstfile)
count = 1
url = f'ftp://{env.ftp_domain}:{vsftpds.port}/'
r = curl.ftp_ssl_upload(urls=[url], fupload=f'{srcfile}', with_stats=True)
r.check_stats(count=count, http_status=226)
self.check_upload(env, vsftpds, docname=docname)
def _rmf(self, path):
if os.path.exists(path):
return os.remove(path)
def check_downloads(self, client, srcfile: str, count: int,
complete: bool = True):
for i in range(count):
@ -138,5 +159,16 @@ class TestVsFTPD:
n=1))
assert False, f'download {dfile} differs:\n{diff}'
def check_upload(self, env, vsftpd: VsFTPD, docname):
srcfile = os.path.join(env.gen_dir, docname)
dstfile = os.path.join(vsftpd.docs_dir, docname)
assert os.path.exists(srcfile)
assert os.path.exists(dstfile)
if not filecmp.cmp(srcfile, dstfile, shallow=False):
diff = "".join(difflib.unified_diff(a=open(srcfile).readlines(),
b=open(dstfile).readlines(),
fromfile=srcfile,
tofile=dstfile,
n=1))
assert False, f'upload {dstfile} differs:\n{diff}'

View file

@ -579,6 +579,37 @@ class CurlClient:
with_profile=with_profile, no_save=no_save,
extra_args=extra_args)
def ftp_upload(self, urls: List[str], fupload,
with_stats: bool = True,
with_profile: bool = False,
extra_args: List[str] = None):
if extra_args is None:
extra_args = []
extra_args.extend([
'--upload-file', fupload
])
if with_stats:
extra_args.extend([
'-w', '%{json}\\n'
])
return self._raw(urls, options=extra_args,
with_stats=with_stats,
with_headers=False,
with_profile=with_profile)
def ftp_ssl_upload(self, urls: List[str], fupload,
with_stats: bool = True,
with_profile: bool = False,
extra_args: List[str] = None):
if extra_args is None:
extra_args = []
extra_args.extend([
'--ssl-reqd',
])
return self.ftp_upload(urls=urls, fupload=fupload,
with_stats=with_stats, with_profile=with_profile,
extra_args=extra_args)
def response_file(self, idx: int):
return os.path.join(self._run_dir, f'download_{idx}.data')

View file

@ -190,16 +190,19 @@ class VsFTPD:
f'anonymous_enable=YES',
f'anon_root={self._docs_dir}',
f'dirmessage_enable=YES',
f'write_enable=YES',
f'anon_upload_enable=YES',
f'log_ftp_protocol=YES',
f'xferlog_enable=YES',
f'xferlog_std_format=YES',
f'xferlog_file={self._error_log}',
f'xferlog_std_format=NO',
f'vsftpd_log_file={self._error_log}',
f'\n',
]
if self._with_ssl:
creds = self.env.get_credentials(self.domain)
conf.extend([
f'ssl_enable=YES',
f'debug_ssl=YES',
f'allow_anon_ssl=YES',
f'rsa_cert_file={creds.cert_file}',
f'rsa_private_key_file={creds.pkey_file}',