1
0
mirror of https://gitlab.com/fdroid/fdroidserver.git synced 2024-11-14 11:00:10 +01:00
fdroidserver/tests/main.TestCase
Hans-Christoph Steiner 18f3acc32e split out options from read_config()
There is no longer any reason for these to be intertwined.

This deliberately avoids touching some files as much as possible because
they are super tangled and due to be replaced.  Those files are:

* fdroidserver/build.py
* fdroidserver/update.py

# Conflicts:
#	tests/testcommon.py

# Conflicts:
#	fdroidserver/btlog.py
#	fdroidserver/import_subcommand.py
2024-05-08 16:26:46 +02:00

282 lines
10 KiB
Python
Executable File

#!/usr/bin/env python3
import inspect
import os
import sys
import pkgutil
import textwrap
import unittest
import tempfile
from unittest import mock
localmodule = os.path.realpath(
os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..')
)
print('localmodule: ' + localmodule)
if localmodule not in sys.path:
sys.path.insert(0, localmodule)
from fdroidserver import common
import fdroidserver.__main__
from testcommon import TmpCwd, TmpPyPath
class MainTest(unittest.TestCase):
'''this tests fdroid.py'''
def test_COMMANDS_check(self):
"""make sure the built in sub-command defs didn't change unintentionally"""
self.assertListEqual(
[x for x in fdroidserver.__main__.COMMANDS.keys()],
[
'build',
'init',
'publish',
'gpgsign',
'update',
'deploy',
'verify',
'checkupdates',
'import',
'install',
'readmeta',
'rewritemeta',
'lint',
'scanner',
'signindex',
'btlog',
'signatures',
'nightly',
'mirror',
],
)
def test_call_init(self):
co = mock.Mock()
with mock.patch('sys.argv', ['', 'init', '-h']):
with mock.patch('fdroidserver.init.main', co):
with mock.patch('sys.exit') as exit_mock:
fdroidserver.__main__.main()
# note: this is sloppy, if `init` changes
# this might need changing too
exit_mock.assert_called_once_with(0)
co.assert_called_once_with()
def test_call_deploy(self):
co = mock.Mock()
with mock.patch('sys.argv', ['', 'deploy', '-h']):
with mock.patch('fdroidserver.deploy.main', co):
with mock.patch('sys.exit') as exit_mock:
fdroidserver.__main__.main()
# note: this is sloppy, if `deploy` changes
# this might need changing too
exit_mock.assert_called_once_with(0)
co.assert_called_once_with()
def test_find_plugins(self):
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
with open('fdroid_testy1.py', 'w') as f:
f.write(
textwrap.dedent(
"""\
fdroid_summary = "ttt"
main = lambda: 'all good'"""
)
)
with TmpPyPath(tmpdir):
plugins = fdroidserver.__main__.find_plugins()
self.assertIn('testy1', plugins.keys())
self.assertEqual(plugins['testy1']['summary'], 'ttt')
self.assertEqual(
__import__(
plugins['testy1']['name'], None, None, ['testy1']
).main(),
'all good',
)
def test_main_plugin_lambda(self):
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
with open('fdroid_testy2.py', 'w') as f:
f.write(
textwrap.dedent(
"""\
fdroid_summary = "ttt"
main = lambda: print('all good')"""
)
)
with TmpPyPath(tmpdir):
with mock.patch('sys.argv', ['', 'testy2']):
with mock.patch('sys.exit') as exit_mock:
fdroidserver.__main__.main()
exit_mock.assert_called_once_with(0)
def test_main_plugin_def(self):
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
with open('fdroid_testy3.py', 'w') as f:
f.write(
textwrap.dedent(
"""\
fdroid_summary = "ttt"
def main():
print('all good')"""
)
)
with TmpPyPath(tmpdir):
with mock.patch('sys.argv', ['', 'testy3']):
with mock.patch('sys.exit') as exit_mock:
fdroidserver.__main__.main()
exit_mock.assert_called_once_with(0)
def test_main_broken_plugin(self):
"""making sure broken plugins get their exceptions through"""
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
with open('fdroid_testy4.py', 'w') as f:
f.write(
textwrap.dedent(
"""\
fdroid_summary = "ttt"
def main():
raise Exception("this plugin is broken")"""
)
)
with TmpPyPath(tmpdir):
with mock.patch('sys.argv', ['', 'testy4']):
with self.assertRaisesRegex(Exception, "this plugin is broken"):
fdroidserver.__main__.main()
def test_main_malicious_plugin(self):
"""The purpose of this test is to make sure code in plugins
doesn't get executed unintentionally.
"""
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
with open('fdroid_testy5.py', 'w') as f:
f.write(
textwrap.dedent(
"""\
fdroid_summary = "ttt"
raise Exception("this plugin is malicious")
def main():
print("evil things")"""
)
)
with TmpPyPath(tmpdir):
with mock.patch('sys.argv', ['', 'lint']):
with mock.patch('sys.exit') as exit_mock:
fdroidserver.__main__.main()
# note: this is sloppy, if `lint` changes
# this might need changing too
exit_mock.assert_called_once_with(0)
def test_main_prevent_plugin_override(self):
"""making sure build-in subcommands cannot be overridden by plugins"""
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
with open('fdroid_signatures.py', 'w') as f:
f.write(
textwrap.dedent(
"""\
fdroid_summary = "ttt"
def main():
raise("plugin overrides don't get prevent!")"""
)
)
with TmpPyPath(tmpdir):
with mock.patch('sys.argv', ['', 'signatures']):
with mock.patch('sys.exit') as exit_mock:
fdroidserver.__main__.main()
# note: this is sloppy, if `signatures` changes
# this might need changing too
self.assertEqual(exit_mock.call_count, 2)
def test_preparse_plugin_lookup_bad_name(self):
self.assertRaises(
ValueError,
fdroidserver.__main__.preparse_plugin,
"some.package",
"/non/existent/module/path",
)
def test_preparse_plugin_lookup_bad_path(self):
self.assertRaises(
ValueError,
fdroidserver.__main__.preparse_plugin,
"fake_module_name",
"/non/existent/module/path",
)
def test_preparse_plugin_lookup_summary_missing(self):
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
with open('fdroid_testy6.py', 'w') as f:
f.write(
textwrap.dedent(
"""\
main = lambda: print('all good')"""
)
)
with TmpPyPath(tmpdir):
p = [x for x in pkgutil.iter_modules() if x[1].startswith('fdroid_')]
module_dir = p[0][0].path
module_name = p[0][1]
self.assertRaises(
NameError,
fdroidserver.__main__.preparse_plugin,
module_name,
module_dir,
)
def test_preparse_plugin_lookup_module_file(self):
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
with open('fdroid_testy7.py', 'w') as f:
f.write(
textwrap.dedent(
"""\
fdroid_summary = "ttt"
main = lambda: pritn('all good')"""
)
)
with TmpPyPath(tmpdir):
p = [x for x in pkgutil.iter_modules() if x[1].startswith('fdroid_')]
module_path = p[0][0].path
module_name = p[0][1]
d = fdroidserver.__main__.preparse_plugin(module_name, module_path)
self.assertDictEqual(d, {'name': 'fdroid_testy7', 'summary': 'ttt'})
def test_preparse_plugin_lookup_module_dir(self):
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
os.mkdir(os.path.join(tmpdir, 'fdroid_testy8'))
with open('fdroid_testy8/__main__.py', 'w') as f:
f.write(
textwrap.dedent(
"""\
fdroid_summary = "ttt"
main = lambda: print('all good')"""
)
)
with open('fdroid_testy8/__init__.py', 'w') as f:
pass
with TmpPyPath(tmpdir):
p = [x for x in pkgutil.iter_modules() if x[1].startswith('fdroid_')]
module_path = p[0][0].path
module_name = p[0][1]
d = fdroidserver.__main__.preparse_plugin(module_name, module_path)
self.assertDictEqual(d, {'name': 'fdroid_testy8', 'summary': 'ttt'})
if __name__ == "__main__":
os.chdir(os.path.dirname(__file__))
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(
"-v",
"--verbose",
action="store_true",
default=False,
help="Spew out even more information than normal",
)
common.options = common.parse_args(parser)
newSuite = unittest.TestSuite()
newSuite.addTest(unittest.makeSuite(MainTest))
unittest.main(failfast=False)