From 160c23a54744b8caec647fb140a45a07267c1496 Mon Sep 17 00:00:00 2001 From: proletarius101 Date: Fri, 22 Dec 2023 17:42:10 +0000 Subject: [PATCH] fix(deploy): add test cases for server webroot mode and fix issues --- fdroidserver/deploy.py | 3 +- tests/deploy.TestCase | 216 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 216 insertions(+), 3 deletions(-) diff --git a/fdroidserver/deploy.py b/fdroidserver/deploy.py index c0222767..b668e2b0 100644 --- a/fdroidserver/deploy.py +++ b/fdroidserver/deploy.py @@ -502,7 +502,8 @@ def update_serverwebroot(serverwebroot, repo_section): url = serverwebroot['url'] logging.info('rsyncing ' + repo_section + ' to ' + url) if options.index_only: - if subprocess.call(rsyncargs + ['--exclude', "*"] + _get_index_includes(repo_section) + [repo_section, url]) != 0: + rsyncargs += ['--include', "*/"] + _get_index_includes(repo_section) + ['--exclude', '*'] + [repo_section, url] + if subprocess.call(rsyncargs) != 0: raise FDroidException() else: excludes = _get_index_excludes(repo_section) diff --git a/tests/deploy.TestCase b/tests/deploy.TestCase index fe6f01cf..4c0c8535 100755 --- a/tests/deploy.TestCase +++ b/tests/deploy.TestCase @@ -144,20 +144,54 @@ class DeployTest(unittest.TestCase): fake_apk = repo / 'fake.apk' with fake_apk.open('w') as fp: fp.write('not an APK, but has the right filename') + fake_index = repo / fdroidserver.deploy.INDEX_FILES[0] + with fake_index.open('w') as fp: + fp.write('not an index, but has the right filename') url = Path('url') url.mkdir() # setup parameters for this test run + fdroidserver.deploy.options = mock.Mock() + fdroidserver.deploy.options.identity_file = None fdroidserver.deploy.options.identity_file = None fdroidserver.deploy.options.index_only = False fdroidserver.deploy.config['make_current_version_link'] = False dest_apk = Path(url) / fake_apk + dest_index = Path(url) / fake_index self.assertFalse(dest_apk.is_file()) - fdroidserver.deploy.options = mock.Mock() - fdroidserver.deploy.options.identity_file = None + self.assertFalse(dest_index.is_file()) + fdroidserver.deploy.update_serverwebroot({'url': str(url)}, 'repo') self.assertTrue(dest_apk.is_file()) + self.assertTrue(dest_index.is_file()) + + def test_update_serverwebroot_in_index_only_mode(self): + os.chdir(self.testdir) + repo = Path('repo') + repo.mkdir(parents=True) + fake_apk = repo / 'fake.apk' + with fake_apk.open('w') as fp: + fp.write('not an APK, but has the right filename') + fake_index = repo / fdroidserver.deploy.INDEX_FILES[0] + with fake_index.open('w') as fp: + fp.write('not an index, but has the right filename') + serverwebroot = Path('serverwebroot') + serverwebroot.mkdir() + + # setup parameters for this test run + fdroidserver.deploy.options.identity_file = None + fdroidserver.deploy.options.index_only = True + fdroidserver.deploy.config['make_current_version_link'] = False + + dest_apk = Path(serverwebroot) / fake_apk + dest_index = Path(serverwebroot) / fake_index + self.assertFalse(dest_apk.is_file()) + self.assertFalse(dest_index.is_file()) + + fdroidserver.deploy.update_serverwebroot(str(serverwebroot), 'repo') + self.assertFalse(dest_apk.is_file()) + self.assertTrue(dest_index.is_file()) @mock.patch.dict(os.environ, clear=True) def test_update_serverwebroot_no_rsync_error(self): @@ -262,6 +296,102 @@ class DeployTest(unittest.TestCase): fdroidserver.deploy.update_serverwebroot({'url': url}, repo_section) self.assertEqual(call_iteration, 3, 'expected 3 invocations of subprocess.call') + def test_update_serverwebroot_make_cur_version_link_in_index_only_mode(self): + # setup parameters for this test run + fdroidserver.deploy.options.no_checksum = True + fdroidserver.deploy.options.identity_file = None + fdroidserver.deploy.options.verbose = False + fdroidserver.deploy.options.quiet = True + fdroidserver.deploy.options.identity_file = None + fdroidserver.deploy.options.index_only = True + fdroidserver.deploy.config['make_current_version_link'] = True + serverwebroot = "example.com:/var/www/fdroid" + repo_section = 'repo' + + # setup function for asserting subprocess.call invocations + call_iteration = 0 + + def update_server_webroot_call(cmd): + nonlocal call_iteration + if call_iteration == 0: + self.assertListEqual( + cmd, + [ + 'rsync', + '--archive', + '--delete-after', + '--safe-links', + '--quiet', + '--include', + "*/", + '--include', + 'repo/entry.jar', + '--include', + 'repo/entry.json', + '--include', + 'repo/entry.json.asc', + '--include', + 'repo/index-v1.jar', + '--include', + 'repo/index-v1.json', + '--include', + 'repo/index-v1.json.asc', + '--include', + 'repo/index-v2.json', + '--include', + 'repo/index-v2.json.asc', + '--include', + 'repo/index.jar', + '--include', + 'repo/index.xml', + '--exclude', + '*', + 'repo', + 'example.com:/var/www/fdroid', + ], + ) + elif call_iteration == 1: + self.assertListEqual( + cmd, + [ + 'rsync', + '--archive', + '--delete-after', + '--safe-links', + '--quiet', + 'repo', + serverwebroot, + ], + ) + elif call_iteration == 2: + self.assertListEqual( + cmd, + [ + 'rsync', + '--archive', + '--delete-after', + '--safe-links', + '--quiet', + 'Sym.apk', + 'Sym.apk.asc', + 'Sym.apk.sig', + 'example.com:/var/www/fdroid', + ], + ) + else: + self.fail('unexpected subprocess.call invocation') + call_iteration += 1 + return 0 + + with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir): + os.mkdir('repo') + os.symlink('repo/com.example.sym.apk', 'Sym.apk') + os.symlink('repo/com.example.sym.apk.asc', 'Sym.apk.asc') + os.symlink('repo/com.example.sym.apk.sig', 'Sym.apk.sig') + with mock.patch('subprocess.call', side_effect=update_server_webroot_call): + fdroidserver.deploy.update_serverwebroot(serverwebroot, repo_section) + self.assertEqual(call_iteration, 1, 'expected 1 invocations of subprocess.call') + def test_update_serverwebroot_with_id_file(self): # setup parameters for this test run fdroidserver.common.options = mock.Mock() @@ -343,6 +473,88 @@ class DeployTest(unittest.TestCase): fdroidserver.deploy.update_serverwebroot({'url': url}, repo_section) self.assertEqual(call_iteration, 2, 'expected 2 invocations of subprocess.call') + def test_update_serverwebroot_with_id_file_in_index_only_mode(self): + # setup parameters for this test run + fdroidserver.deploy.options.no_chcksum = False + fdroidserver.deploy.options.verbose = True + fdroidserver.deploy.options.quiet = False + fdroidserver.deploy.options.identity_file = None + fdroidserver.deploy.options.index_only = True + fdroidserver.deploy.config['identity_file'] = './id_rsa' + fdroidserver.deploy.config['make_current_version_link'] = False + serverwebroot = "example.com:/var/www/fdroid" + repo_section = 'archive' + + # setup function for asserting subprocess.call invocations + call_iteration = 0 + + def update_server_webroot_call(cmd): + nonlocal call_iteration + if call_iteration == 0: + self.assertListEqual( + cmd, + [ + 'rsync', + '--archive', + '--delete-after', + '--safe-links', + '--verbose', + '-e', + 'ssh -oBatchMode=yes -oIdentitiesOnly=yes -i ' + + fdroidserver.deploy.config['identity_file'], + '--include', + "*/", + '--include', + 'archive/entry.jar', + '--include', + 'archive/entry.json', + '--include', + 'archive/entry.json.asc', + '--include', + 'archive/index-v1.jar', + '--include', + 'archive/index-v1.json', + '--include', + 'archive/index-v1.json.asc', + '--include', + 'archive/index-v2.json', + '--include', + 'archive/index-v2.json.asc', + '--include', + 'archive/index.jar', + '--include', + 'archive/index.xml', + '--exclude', + "*", + 'archive', + serverwebroot, + ], + ) + elif call_iteration == 1: + self.assertListEqual( + cmd, + [ + 'rsync', + '--archive', + '--delete-after', + '--safe-links', + '--verbose', + '-e', + 'ssh -oBatchMode=yes -oIdentitiesOnly=yes -i ' + + fdroidserver.deploy.config['identity_file'], + 'archive', + serverwebroot, + ], + ) + else: + self.fail('unexpected subprocess.call invocation') + call_iteration += 1 + return 0 + + with mock.patch('subprocess.call', side_effect=update_server_webroot_call): + fdroidserver.deploy.update_serverwebroot(serverwebroot, repo_section) + self.assertEqual(call_iteration, 1, 'expected 1 invocations of subprocess.call') + @unittest.skipIf( not os.getenv('VIRUSTOTAL_API_KEY'), 'VIRUSTOTAL_API_KEY is not set' )