mirror of
https://gitlab.com/fdroid/fdroidserver.git
synced 2024-08-15 02:40:09 +02:00
Windows seems to require this, otherwise this happens: Traceback (most recent call last): File "tests/update.TestCase", line 737, in test_translate_per_build_anti_features apps = fdroidserver.metadata.read_metadata(xref=True) File "C:\Users\travis\build\fdroidtravis\fdroidserver\fdroidserver\metadata.py", line 813, in read_metadata app = parse_metadata(metadatapath, appid in check_vcs, refresh) File "C:\Users\travis\build\fdroidtravis\fdroidserver\fdroidserver\metadata.py", line 1023, in parse_metadata parse_yaml_metadata(mf, app) File "C:\Users\travis\build\fdroidtravis\fdroidserver\fdroidserver\metadata.py", line 1073, in parse_yaml_metadata yamldata = yaml.safe_load(mf) File "C:\python37\lib\site-packages\yaml\__init__.py", line 162, in safe_load return load(stream, SafeLoader) File "C:\python37\lib\site-packages\yaml\__init__.py", line 112, in load loader = Loader(stream) File "C:\python37\lib\site-packages\yaml\loader.py", line 34, in __init__ Reader.__init__(self, stream) File "C:\python37\lib\site-packages\yaml\reader.py", line 85, in __init__ self.determine_encoding() File "C:\python37\lib\site-packages\yaml\reader.py", line 124, in determine_encoding self.update_raw() File "C:\python37\lib\site-packages\yaml\reader.py", line 178, in update_raw data = self.stream.read(size) File "C:\python37\lib\encodings\cp1252.py", line 23, in decode return codecs.charmap_decode(input,self.errors,decoding_table)[0] UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 37: character maps to <undefined>
1128 lines
41 KiB
Python
Executable File
1128 lines
41 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import io
|
|
import logging
|
|
import optparse
|
|
import os
|
|
import random
|
|
import shutil
|
|
import sys
|
|
import unittest
|
|
from unittest import mock
|
|
import tempfile
|
|
import textwrap
|
|
from collections import OrderedDict
|
|
from pathlib import Path
|
|
|
|
|
|
import yaml
|
|
from testcommon import TmpCwd
|
|
|
|
|
|
try:
|
|
from yaml import CSafeLoader as SafeLoader
|
|
except ImportError:
|
|
from yaml import SafeLoader
|
|
|
|
localmodule = Path(__file__).resolve().parent.parent
|
|
print('localmodule: ' + str(localmodule))
|
|
if localmodule not in sys.path:
|
|
sys.path.insert(0, str(localmodule))
|
|
|
|
|
|
import fdroidserver.common
|
|
import fdroidserver.metadata
|
|
from fdroidserver.exception import MetaDataException
|
|
|
|
|
|
class MetadataTest(unittest.TestCase):
|
|
'''fdroidserver/metadata.py'''
|
|
|
|
def setUp(self):
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
self.basedir = localmodule / 'tests'
|
|
self.tmpdir = localmodule / '.testfiles'
|
|
self.tmpdir.mkdir(exist_ok=True)
|
|
# TODO: Python3.6: Accepts a path-like object.
|
|
os.chdir(str(self.basedir))
|
|
|
|
def test_FieldValidator_BitcoinAddress(self):
|
|
validator = None
|
|
for vali in fdroidserver.metadata.valuetypes:
|
|
if vali.name == 'Bitcoin address':
|
|
validator = vali
|
|
break
|
|
self.assertIsNotNone(validator, "could not find 'Bitcoin address' validator")
|
|
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
|
|
# some valid addresses (P2PKH, P2SH, Bech32)
|
|
self.assertIsNone(
|
|
validator.check('1BrrrrErsrWetrTrnrrrrm4GFg7xJaNVN2', 'fake.app.id')
|
|
)
|
|
self.assertIsNone(
|
|
validator.check('3JrrrrWrEZr3rNrrvrecrnyirrnqRhWNLy', 'fake.app.id')
|
|
)
|
|
self.assertIsNone(
|
|
validator.check('bc1qar0srrr7xrkvr5lr43lrdnwrre5rgtrzrf5rrq', 'fake.app.id')
|
|
)
|
|
|
|
# some invalid addresses
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'21BvMrSYsrWrtrrlL5A10mlGFr7rrarrN2',
|
|
'fake.app.id',
|
|
)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'5Hrgr3ur5rGLrfKrrrrrrHSrqJrroGrrzrQrrrrrrLNrsrDrrrA',
|
|
'fake.app.id',
|
|
)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'92rr46rUrgTrrromrVrirW6r1rrrdrerrdbJrrrhrCsYrrrrrrc',
|
|
'fake.app.id',
|
|
)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'K1BvMrSYsrWrtrrrn5Au4m4GFr7rrarrN2',
|
|
'fake.app.id',
|
|
)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'L1BvMrSYsrWrtrrrn5Au4m4GFr7rrarrN2',
|
|
'fake.app.id',
|
|
)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'tb1qw5r8drrejxrrg4y5rrrrrraryrrrrwrkxrjrsx',
|
|
'fake.app.id',
|
|
)
|
|
|
|
def test_FieldValidator_LitecoinAddress(self):
|
|
validator = None
|
|
for vali in fdroidserver.metadata.valuetypes:
|
|
if vali.name == 'Litecoin address':
|
|
validator = vali
|
|
break
|
|
self.assertIsNotNone(validator, "could not find 'Litecoin address' validator")
|
|
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
|
|
# some valid addresses (L, M, 3)
|
|
self.assertIsNone(
|
|
validator.check('LgeGrrrrJAxyXprrPrrBrrX5Qrrrrrrrrd', 'fake.app.id')
|
|
)
|
|
self.assertIsNone(
|
|
validator.check('MrrrrrrrJAxyXpanPtrrRAX5QHxvUJo8id', 'fake.app.id')
|
|
)
|
|
self.assertIsNone(validator.check('3rereVr9rAryrranrrrrrAXrrHx', 'fake.app.id'))
|
|
|
|
# some invalid addresses (various special use/testnet addresses, invalid chars)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'21BvMrSYsrWrtrrrn5Au4l4GFr7rrarrN2',
|
|
'fake.app.id',
|
|
)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'5Hrgr3ur5rGLrfKrrrrrr1SrqJrroGrrzrQrrrrrrLNrsrDrrrA',
|
|
'fake.app.id',
|
|
)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'92rr46rUrgTrrromrVrirW6r1rrrdrerrdbJrrrhrCsYrrrrrrc',
|
|
'fake.app.id',
|
|
)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'K1BvMrSYsrWrtrrrn5Au4m4GFr7rrarrN2',
|
|
'fake.app.id',
|
|
)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'L0000rSYsrWrtrrrn5Au4m4GFr7rrarrN2',
|
|
'fake.app.id',
|
|
)
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
validator.check,
|
|
'tb1qw5r8drrejxrrg4y5rrrrrraryrrrrwrkxrjrsx',
|
|
'fake.app.id',
|
|
)
|
|
|
|
def test_valid_funding_yml_regex(self):
|
|
"""Check the regex can find all the cases"""
|
|
with (self.basedir / 'funding-usernames.yaml').open() as fp:
|
|
data = yaml.load(fp, Loader=SafeLoader)
|
|
|
|
for k, entries in data.items():
|
|
for entry in entries:
|
|
m = fdroidserver.metadata.VALID_USERNAME_REGEX.match(entry)
|
|
if k == 'custom':
|
|
pass
|
|
elif k == 'bad':
|
|
self.assertIsNone(
|
|
m, 'this is an invalid %s username: {%s}' % (k, entry)
|
|
)
|
|
else:
|
|
self.assertIsNotNone(
|
|
m, 'this is a valid %s username: {%s}' % (k, entry)
|
|
)
|
|
|
|
def test_read_metadata(self):
|
|
def _build_yaml_representer(dumper, data):
|
|
'''Creates a YAML representation of a Build instance'''
|
|
return dumper.represent_dict(data)
|
|
|
|
self.maxDiff = None
|
|
|
|
config = dict()
|
|
fdroidserver.common.fill_config_defaults(config)
|
|
fdroidserver.common.config = config
|
|
fdroidserver.metadata.warnings_action = None
|
|
|
|
apps = fdroidserver.metadata.read_metadata()
|
|
for appid in (
|
|
'org.smssecure.smssecure',
|
|
'org.adaway',
|
|
'org.videolan.vlc',
|
|
'com.politedroid',
|
|
):
|
|
savepath = Path('metadata/dump') / (appid + '.yaml')
|
|
frommeta = dict(apps[appid])
|
|
self.assertTrue(appid in apps)
|
|
with savepath.open('r') as f:
|
|
from_yaml = yaml.load(f, Loader=SafeLoader)
|
|
self.assertEqual(frommeta, from_yaml)
|
|
# comment above assert and uncomment below to update test
|
|
# files when new metadata fields are added
|
|
# with savepath.open('w') as f:
|
|
# yaml.add_representer(fdroidserver.metadata.Build, _build_yaml_representer)
|
|
# yaml.dump(frommeta, f, default_flow_style=False)
|
|
|
|
def test_rewrite_yaml_fakeotaupdate(self):
|
|
# TODO: Pytohn3.6: The dir parameter now accepts a path-like object.
|
|
with tempfile.TemporaryDirectory(dir=str(self.tmpdir)) as testdir:
|
|
testdir = Path(testdir)
|
|
fdroidserver.common.config = {'accepted_formats': ['yml']}
|
|
fdroidserver.metadata.warnings_action = None
|
|
|
|
# rewrite metadata
|
|
allapps = fdroidserver.metadata.read_metadata()
|
|
for appid, app in allapps.items():
|
|
if appid == 'fake.ota.update':
|
|
fdroidserver.metadata.write_metadata(
|
|
testdir / (appid + '.yml'), app
|
|
)
|
|
|
|
# assert rewrite result
|
|
self.maxDiff = None
|
|
file_name = 'fake.ota.update.yml'
|
|
self.assertEqual(
|
|
(testdir / file_name).read_text(encoding='utf-8'),
|
|
(Path('metadata-rewrite-yml') / file_name).read_text(encoding='utf-8'),
|
|
)
|
|
|
|
def test_rewrite_yaml_fdroidclient(self):
|
|
# TODO: Pytohn3.6: The dir parameter now accepts a path-like object.
|
|
with tempfile.TemporaryDirectory(dir=str(self.tmpdir)) as testdir:
|
|
testdir = Path(testdir)
|
|
fdroidserver.common.config = {'accepted_formats': ['yml']}
|
|
|
|
# rewrite metadata
|
|
allapps = fdroidserver.metadata.read_metadata()
|
|
for appid, app in allapps.items():
|
|
if appid == 'org.fdroid.fdroid':
|
|
fdroidserver.metadata.write_metadata(
|
|
testdir / (appid + '.yml'), app
|
|
)
|
|
|
|
# assert rewrite result
|
|
self.maxDiff = None
|
|
file_name = 'org.fdroid.fdroid.yml'
|
|
self.assertEqual(
|
|
(testdir / file_name).read_text(encoding='utf-8'),
|
|
(Path('metadata-rewrite-yml') / file_name).read_text(encoding='utf-8'),
|
|
)
|
|
|
|
def test_rewrite_yaml_special_build_params(self):
|
|
# TODO: Pytohn3.6: The dir parameter now accepts a path-like object.
|
|
with tempfile.TemporaryDirectory(dir=str(self.tmpdir)) as testdir:
|
|
testdir = Path(testdir)
|
|
|
|
# rewrite metadata
|
|
allapps = fdroidserver.metadata.read_metadata()
|
|
for appid, app in allapps.items():
|
|
if appid == 'app.with.special.build.params':
|
|
fdroidserver.metadata.write_metadata(
|
|
testdir / (appid + '.yml'), app
|
|
)
|
|
|
|
# assert rewrite result
|
|
self.maxDiff = None
|
|
file_name = 'app.with.special.build.params.yml'
|
|
self.assertEqual(
|
|
(testdir / file_name).read_text(encoding='utf-8'),
|
|
(Path('metadata-rewrite-yml') / file_name).read_text(encoding='utf-8'),
|
|
)
|
|
|
|
def test_post_parse_yaml_metadata(self):
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
yamldata = OrderedDict()
|
|
builds = []
|
|
yamldata['Builds'] = builds
|
|
build = OrderedDict()
|
|
builds.append(build)
|
|
|
|
build['versionCode'] = 1.1
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
fdroidserver.metadata.post_parse_yaml_metadata,
|
|
yamldata,
|
|
)
|
|
|
|
build['versionCode'] = '1'
|
|
self.assertRaises(
|
|
fdroidserver.exception.MetaDataException,
|
|
fdroidserver.metadata.post_parse_yaml_metadata,
|
|
yamldata,
|
|
)
|
|
|
|
build['versionCode'] = 1
|
|
build['versionName'] = 1
|
|
fdroidserver.metadata.post_parse_yaml_metadata(yamldata)
|
|
self.assertNotEqual(1, yamldata['Builds'][0]['versionName'])
|
|
self.assertEqual('1', yamldata['Builds'][0]['versionName'])
|
|
self.assertEqual(1, yamldata['Builds'][0]['versionCode'])
|
|
|
|
build['versionName'] = 1.0
|
|
fdroidserver.metadata.post_parse_yaml_metadata(yamldata)
|
|
self.assertNotEqual(1.0, yamldata['Builds'][0]['versionName'])
|
|
self.assertEqual('1.0', yamldata['Builds'][0]['versionName'])
|
|
|
|
build['commit'] = 1.0
|
|
fdroidserver.metadata.post_parse_yaml_metadata(yamldata)
|
|
self.assertNotEqual(1.0, yamldata['Builds'][0]['commit'])
|
|
self.assertEqual('1.0', yamldata['Builds'][0]['commit'])
|
|
|
|
teststr = '98234fab134b'
|
|
build['commit'] = teststr
|
|
fdroidserver.metadata.post_parse_yaml_metadata(yamldata)
|
|
self.assertEqual(teststr, yamldata['Builds'][0]['commit'])
|
|
|
|
testcommitid = 1234567890
|
|
build['commit'] = testcommitid
|
|
fdroidserver.metadata.post_parse_yaml_metadata(yamldata)
|
|
self.assertNotEqual(testcommitid, yamldata['Builds'][0]['commit'])
|
|
self.assertEqual('1234567890', yamldata['Builds'][0]['commit'])
|
|
|
|
def test_read_metadata_sort_by_time(self):
|
|
# TODO: Pytohn3.6: The dir parameter now accepts a path-like object.
|
|
with tempfile.TemporaryDirectory(dir=str(self.tmpdir)) as testdir, TmpCwd(
|
|
testdir
|
|
):
|
|
testdir = Path(testdir)
|
|
metadatadir = testdir / 'metadata'
|
|
metadatadir.mkdir()
|
|
|
|
randomlist = []
|
|
randomapps = list((self.basedir / 'metadata').glob('*.yml'))
|
|
random.shuffle(randomapps)
|
|
i = 1
|
|
for f in randomapps:
|
|
# TODO: Pytohn3.6: The parameter now accepts a path-like object.
|
|
shutil.copy(str(f), str(metadatadir))
|
|
new = metadatadir / f.name
|
|
stat = new.stat()
|
|
# TODO: Changed in version 3.6: Accepts a path-like object.
|
|
os.utime(str(new), (stat.st_ctime, stat.st_mtime + i))
|
|
# prepend new item so newest is always first
|
|
randomlist = [f.stem] + randomlist
|
|
i += 1
|
|
allapps = fdroidserver.metadata.read_metadata(sort_by_time=True)
|
|
allappids = []
|
|
for appid, app in allapps.items():
|
|
allappids.append(appid)
|
|
self.assertEqual(randomlist, allappids)
|
|
|
|
def test_parse_yaml_metadata_unknown_app_field(self):
|
|
mf = io.StringIO(
|
|
textwrap.dedent(
|
|
"""\
|
|
AutoName: F-Droid
|
|
RepoType: git
|
|
Builds: []
|
|
bad: value"""
|
|
)
|
|
)
|
|
mf.name = 'mock_filename.yaml'
|
|
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
|
with self.assertRaises(MetaDataException):
|
|
fdroidserver.metadata.parse_yaml_metadata(mf, {})
|
|
|
|
def test_parse_yaml_metadata_unknown_build_flag(self):
|
|
mf = io.StringIO(
|
|
textwrap.dedent(
|
|
"""\
|
|
AutoName: F-Droid
|
|
RepoType: git
|
|
Builds:
|
|
- bad: value"""
|
|
)
|
|
)
|
|
mf.name = 'mock_filename.yaml'
|
|
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
|
with self.assertRaises(MetaDataException):
|
|
fdroidserver.metadata.parse_yaml_metadata(mf, {})
|
|
|
|
def test_parse_yaml_srclib_corrupt_file(self):
|
|
# TODO: Pytohn3.6: The dir parameter now accepts a path-like object.
|
|
with tempfile.TemporaryDirectory(dir=str(self.tmpdir)) as testdir:
|
|
testdir = Path(testdir)
|
|
srclibfile = testdir / 'srclib/mock.yml'
|
|
srclibfile.parent.mkdir()
|
|
with srclibfile.open('w') as fp:
|
|
fp.write(
|
|
textwrap.dedent(
|
|
"""
|
|
- RepoType: git
|
|
- Repo: https://github.com/realm/realm-js.git
|
|
"""
|
|
)
|
|
)
|
|
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
|
with self.assertRaises(MetaDataException):
|
|
fdroidserver.metadata.parse_yaml_srclib(srclibfile)
|
|
|
|
def test_write_yaml_with_placeholder_values(self):
|
|
mf = io.StringIO()
|
|
|
|
app = fdroidserver.metadata.App()
|
|
app.Categories = ['None']
|
|
app.SourceCode = "https://gitlab.com/fdroid/fdroidclient.git"
|
|
app.IssueTracker = "https://gitlab.com/fdroid/fdroidclient/issues"
|
|
app.RepoType = 'git'
|
|
app.Repo = 'https://gitlab.com/fdroid/fdroidclient.git'
|
|
app.AutoUpdateMode = 'None'
|
|
app.UpdateCheckMode = 'Tags'
|
|
build = fdroidserver.metadata.Build()
|
|
build.versionName = 'Unknown' # taken from fdroidserver/import.py
|
|
build.versionCode = '0' # taken from fdroidserver/import.py
|
|
build.disable = 'Generated by import.py ...'
|
|
build.commit = 'Unknown'
|
|
build.gradle = [True]
|
|
app['Builds'] = [build]
|
|
|
|
fdroidserver.metadata.write_yaml(mf, app)
|
|
|
|
mf.seek(0)
|
|
self.assertEqual(
|
|
mf.read(),
|
|
textwrap.dedent(
|
|
"""\
|
|
Categories:
|
|
- None
|
|
License: Unknown
|
|
SourceCode: https://gitlab.com/fdroid/fdroidclient.git
|
|
IssueTracker: https://gitlab.com/fdroid/fdroidclient/issues
|
|
|
|
RepoType: git
|
|
Repo: https://gitlab.com/fdroid/fdroidclient.git
|
|
|
|
Builds:
|
|
- versionName: Unknown
|
|
versionCode: 0
|
|
disable: Generated by import.py ...
|
|
commit: Unknown
|
|
gradle:
|
|
- true
|
|
|
|
AutoUpdateMode: None
|
|
UpdateCheckMode: Tags
|
|
"""
|
|
),
|
|
)
|
|
|
|
def test_parse_yaml_metadata_prebuild_list(self):
|
|
mf = io.StringIO(
|
|
textwrap.dedent(
|
|
"""\
|
|
AutoName: F-Droid
|
|
RepoType: git
|
|
Builds:
|
|
- versionCode: 1
|
|
versionName: v0.1.0
|
|
sudo:
|
|
- apt-get update
|
|
- apt-get install -y whatever
|
|
- sed -i -e 's/<that attr="bad"/<that attr="good"/' ~/.whatever/config.xml
|
|
init:
|
|
- bash generate_some_file.sh
|
|
- sed -i -e 'g/what/ever/' /some/file
|
|
prebuild:
|
|
- npm something
|
|
- echo 'important setting' >> /a/file
|
|
build:
|
|
- ./gradlew someSpecialTask
|
|
- sed -i 'd/that wrong config/' gradle.properties
|
|
- ./gradlew compile
|
|
"""
|
|
)
|
|
)
|
|
mf.name = 'mock_filename.yaml'
|
|
mf.seek(0)
|
|
result = {}
|
|
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
|
fdroidserver.metadata.parse_yaml_metadata(mf, result)
|
|
self.maxDiff = None
|
|
self.assertDictEqual(
|
|
result,
|
|
{
|
|
'AutoName': 'F-Droid',
|
|
'RepoType': 'git',
|
|
'Builds': [
|
|
{
|
|
'versionCode': 1,
|
|
'versionName': 'v0.1.0',
|
|
'sudo': "apt-get update && "
|
|
"apt-get install -y whatever && "
|
|
"sed -i -e 's/<that attr=\"bad\"/<that attr=\"good\"/' ~/.whatever/config.xml",
|
|
'init': "bash generate_some_file.sh && "
|
|
"sed -i -e 'g/what/ever/' /some/file",
|
|
'prebuild': "npm something && echo 'important setting' >> /a/file",
|
|
'build': "./gradlew someSpecialTask && "
|
|
"sed -i 'd/that wrong config/' gradle.properties && "
|
|
"./gradlew compile",
|
|
}
|
|
],
|
|
},
|
|
)
|
|
|
|
def test_parse_yaml_metadata_prebuild_strings(self):
|
|
mf = io.StringIO(
|
|
textwrap.dedent(
|
|
"""\
|
|
AutoName: F-Droid
|
|
RepoType: git
|
|
Builds:
|
|
- versionCode: 1
|
|
versionName: v0.1.0
|
|
sudo: |-
|
|
apt-get update && apt-get install -y whatever && sed -i -e 's/<that attr="bad"/<that attr="good"/' ~/.whatever/config.xml
|
|
init: bash generate_some_file.sh && sed -i -e 'g/what/ever/' /some/file
|
|
prebuild: npm something && echo 'important setting' >> /a/file
|
|
build: |-
|
|
./gradlew someSpecialTask && sed -i 'd/that wrong config/' gradle.properties && ./gradlew compile
|
|
"""
|
|
)
|
|
)
|
|
mf.name = 'mock_filename.yaml'
|
|
mf.seek(0)
|
|
result = {}
|
|
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
|
fdroidserver.metadata.parse_yaml_metadata(mf, result)
|
|
self.maxDiff = None
|
|
self.assertDictEqual(
|
|
result,
|
|
{
|
|
'AutoName': 'F-Droid',
|
|
'RepoType': 'git',
|
|
'Builds': [
|
|
{
|
|
'versionCode': 1,
|
|
'versionName': 'v0.1.0',
|
|
'sudo': "apt-get update && "
|
|
"apt-get install -y whatever && "
|
|
"sed -i -e 's/<that attr=\"bad\"/<that attr=\"good\"/' ~/.whatever/config.xml",
|
|
'init': "bash generate_some_file.sh && "
|
|
"sed -i -e 'g/what/ever/' /some/file",
|
|
'prebuild': "npm something && echo 'important setting' >> /a/file",
|
|
'build': "./gradlew someSpecialTask && "
|
|
"sed -i 'd/that wrong config/' gradle.properties && "
|
|
"./gradlew compile",
|
|
}
|
|
],
|
|
},
|
|
)
|
|
|
|
def test_parse_yaml_metadata_prebuild_string(self):
|
|
mf = io.StringIO(
|
|
textwrap.dedent(
|
|
"""\
|
|
AutoName: F-Droid
|
|
RepoType: git
|
|
Builds:
|
|
- versionCode: 1
|
|
versionName: v0.1.0
|
|
prebuild: |-
|
|
a && b && sed -i 's,a,b,'
|
|
"""
|
|
)
|
|
)
|
|
mf.name = 'mock_filename.yaml'
|
|
mf.seek(0)
|
|
result = {}
|
|
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
|
fdroidserver.metadata.parse_yaml_metadata(mf, result)
|
|
self.assertDictEqual(
|
|
result,
|
|
{
|
|
'AutoName': 'F-Droid',
|
|
'RepoType': 'git',
|
|
'Builds': [
|
|
{
|
|
'versionCode': 1,
|
|
'versionName': 'v0.1.0',
|
|
'prebuild': "a && b && " "sed -i 's,a,b,'",
|
|
}
|
|
],
|
|
},
|
|
)
|
|
|
|
def test_parse_yaml_provides_should_be_ignored(self):
|
|
mf = io.StringIO(
|
|
textwrap.dedent(
|
|
"""\
|
|
Provides: this.is.deprecated
|
|
AutoName: F-Droid
|
|
RepoType: git
|
|
Builds:
|
|
- versionCode: 1
|
|
versionName: v0.1.0
|
|
prebuild: |-
|
|
a && b && sed -i 's,a,b,'
|
|
"""
|
|
)
|
|
)
|
|
mf.name = 'mock_filename.yaml'
|
|
mf.seek(0)
|
|
result = {}
|
|
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
|
fdroidserver.metadata.parse_yaml_metadata(mf, result)
|
|
self.assertNotIn('Provides', result)
|
|
self.assertNotIn('provides', result)
|
|
|
|
def test_write_yaml_1_line_scripts_as_string(self):
|
|
mf = io.StringIO()
|
|
app = fdroidserver.metadata.App()
|
|
app.Categories = ['None']
|
|
app['Builds'] = []
|
|
build = fdroidserver.metadata.Build()
|
|
build.versionCode = 102030
|
|
build.versionName = 'v1.2.3'
|
|
build.sudo = "chmod +rwx /opt"
|
|
build.init = "sed -i -e 'g/what/ever/' /some/file"
|
|
build.prebuild = "sed -i 'd/that wrong config/' gradle.properties"
|
|
build.build = "./gradlew compile"
|
|
app['Builds'].append(build)
|
|
fdroidserver.metadata.write_yaml(mf, app)
|
|
mf.seek(0)
|
|
self.assertEqual(
|
|
mf.read(),
|
|
textwrap.dedent(
|
|
"""\
|
|
Categories:
|
|
- None
|
|
License: Unknown
|
|
|
|
Builds:
|
|
- versionName: v1.2.3
|
|
versionCode: 102030
|
|
sudo: chmod +rwx /opt
|
|
init: sed -i -e 'g/what/ever/' /some/file
|
|
prebuild: sed -i 'd/that wrong config/' gradle.properties
|
|
build: ./gradlew compile
|
|
|
|
AutoUpdateMode: None
|
|
UpdateCheckMode: None
|
|
"""
|
|
),
|
|
)
|
|
|
|
def test_write_yaml_1_line_scripts_as_list(self):
|
|
mf = io.StringIO()
|
|
app = fdroidserver.metadata.App()
|
|
app.Categories = ['None']
|
|
app['Builds'] = []
|
|
build = fdroidserver.metadata.Build()
|
|
build.versionCode = 102030
|
|
build.versionName = 'v1.2.3'
|
|
build.sudo = ["chmod +rwx /opt"]
|
|
build.init = ["sed -i -e 'g/what/ever/' /some/file"]
|
|
build.prebuild = ["sed -i 'd/that wrong config/' gradle.properties"]
|
|
build.build = ["./gradlew compile"]
|
|
app['Builds'].append(build)
|
|
fdroidserver.metadata.write_yaml(mf, app)
|
|
mf.seek(0)
|
|
self.assertEqual(
|
|
mf.read(),
|
|
textwrap.dedent(
|
|
"""\
|
|
Categories:
|
|
- None
|
|
License: Unknown
|
|
|
|
Builds:
|
|
- versionName: v1.2.3
|
|
versionCode: 102030
|
|
sudo: chmod +rwx /opt
|
|
init: sed -i -e 'g/what/ever/' /some/file
|
|
prebuild: sed -i 'd/that wrong config/' gradle.properties
|
|
build: ./gradlew compile
|
|
|
|
AutoUpdateMode: None
|
|
UpdateCheckMode: None
|
|
"""
|
|
),
|
|
)
|
|
|
|
def test_write_yaml_multiline_scripts_from_list(self):
|
|
mf = io.StringIO()
|
|
app = fdroidserver.metadata.App()
|
|
app.Categories = ['None']
|
|
app['Builds'] = []
|
|
build = fdroidserver.metadata.Build()
|
|
build.versionCode = 102030
|
|
build.versionName = 'v1.2.3'
|
|
build.sudo = [
|
|
"apt-get update",
|
|
"apt-get install -y whatever",
|
|
"sed -i -e 's/<that attr=\"bad\"/<that attr=\"good\"/' ~/.whatever/config.xml",
|
|
]
|
|
build.init = [
|
|
"bash generate_some_file.sh",
|
|
"sed -i -e 'g/what/ever/' /some/file",
|
|
]
|
|
build.prebuild = ["npm something", "echo 'important setting' >> /a/file"]
|
|
build.build = [
|
|
"./gradlew someSpecialTask",
|
|
"sed -i 'd/that wrong config/' gradle.properties",
|
|
"./gradlew compile",
|
|
]
|
|
app['Builds'].append(build)
|
|
fdroidserver.metadata.write_yaml(mf, app)
|
|
mf.seek(0)
|
|
self.assertEqual(
|
|
mf.read(),
|
|
textwrap.dedent(
|
|
"""\
|
|
Categories:
|
|
- None
|
|
License: Unknown
|
|
|
|
Builds:
|
|
- versionName: v1.2.3
|
|
versionCode: 102030
|
|
sudo:
|
|
- apt-get update
|
|
- apt-get install -y whatever
|
|
- sed -i -e 's/<that attr="bad"/<that attr="good"/' ~/.whatever/config.xml
|
|
init:
|
|
- bash generate_some_file.sh
|
|
- sed -i -e 'g/what/ever/' /some/file
|
|
prebuild:
|
|
- npm something
|
|
- echo 'important setting' >> /a/file
|
|
build:
|
|
- ./gradlew someSpecialTask
|
|
- sed -i 'd/that wrong config/' gradle.properties
|
|
- ./gradlew compile
|
|
|
|
AutoUpdateMode: None
|
|
UpdateCheckMode: None
|
|
"""
|
|
),
|
|
)
|
|
|
|
def test_write_yaml_multiline_scripts_from_string(self):
|
|
mf = io.StringIO()
|
|
app = fdroidserver.metadata.App()
|
|
app.Categories = ['None']
|
|
app['Builds'] = []
|
|
build = fdroidserver.metadata.Build()
|
|
build.versionCode = 102030
|
|
build.versionName = 'v1.2.3'
|
|
build.sudo = "apt-get update && apt-get install -y whatever && sed -i -e 's/<that attr=\"bad\"/<that attr=\"good\"/' ~/.whatever/config.xml"
|
|
build.init = "bash generate_some_file.sh && sed -i -e 'g/what/ever/' /some/file"
|
|
build.prebuild = "npm something && echo 'important setting' >> /a/file"
|
|
build.build = "./gradlew someSpecialTask && sed -i 'd/that wrong config/' gradle.properties && ./gradlew compile"
|
|
app['Builds'].append(build)
|
|
fdroidserver.metadata.write_yaml(mf, app)
|
|
mf.seek(0)
|
|
self.assertEqual(
|
|
mf.read(),
|
|
textwrap.dedent(
|
|
"""\
|
|
Categories:
|
|
- None
|
|
License: Unknown
|
|
|
|
Builds:
|
|
- versionName: v1.2.3
|
|
versionCode: 102030
|
|
sudo:
|
|
- apt-get update
|
|
- apt-get install -y whatever
|
|
- sed -i -e 's/<that attr="bad"/<that attr="good"/' ~/.whatever/config.xml
|
|
init:
|
|
- bash generate_some_file.sh
|
|
- sed -i -e 'g/what/ever/' /some/file
|
|
prebuild:
|
|
- npm something
|
|
- echo 'important setting' >> /a/file
|
|
build:
|
|
- ./gradlew someSpecialTask
|
|
- sed -i 'd/that wrong config/' gradle.properties
|
|
- ./gradlew compile
|
|
|
|
AutoUpdateMode: None
|
|
UpdateCheckMode: None
|
|
"""
|
|
),
|
|
)
|
|
|
|
def test_write_yaml_make_sure_provides_does_not_get_written(self):
|
|
mf = io.StringIO()
|
|
app = fdroidserver.metadata.App()
|
|
app.Categories = ['None']
|
|
app.Provides = 'this.is.deprecated'
|
|
app['Builds'] = []
|
|
build = fdroidserver.metadata.Build()
|
|
build.versionCode = 102030
|
|
build.versionName = 'v1.2.3'
|
|
build.gradle = ['yes']
|
|
app['Builds'].append(build)
|
|
fdroidserver.metadata.write_yaml(mf, app)
|
|
mf.seek(0)
|
|
self.assertEqual(
|
|
mf.read(),
|
|
textwrap.dedent(
|
|
"""\
|
|
Categories:
|
|
- None
|
|
License: Unknown
|
|
|
|
Builds:
|
|
- versionName: v1.2.3
|
|
versionCode: 102030
|
|
gradle:
|
|
- yes
|
|
|
|
AutoUpdateMode: None
|
|
UpdateCheckMode: None
|
|
"""
|
|
),
|
|
)
|
|
|
|
def test_parse_yaml_srclib_unknown_key(self):
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
|
with Path('test.yml').open('w', encoding='utf-8') as f:
|
|
f.write(
|
|
textwrap.dedent(
|
|
'''\
|
|
RepoType: git
|
|
Repo: https://example.com/test.git
|
|
Evil: I should not be here.
|
|
'''
|
|
)
|
|
)
|
|
with self.assertRaisesRegex(
|
|
MetaDataException,
|
|
"Invalid srclib metadata: " "unknown key 'Evil' in " "'test.yml'",
|
|
):
|
|
fdroidserver.metadata.parse_yaml_srclib(Path('test.yml'))
|
|
|
|
def test_parse_yaml_srclib_does_not_exists(self):
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
with self.assertRaisesRegex(
|
|
MetaDataException,
|
|
"Invalid scrlib metadata: "
|
|
r"'non(/|\\)existent-test-srclib.yml' "
|
|
"does not exist",
|
|
):
|
|
fdroidserver.metadata.parse_yaml_srclib(
|
|
Path('non/existent-test-srclib.yml')
|
|
)
|
|
|
|
def test_parse_yaml_srclib_simple(self):
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
|
with Path('simple.yml').open('w', encoding='utf-8') as f:
|
|
f.write(
|
|
textwrap.dedent(
|
|
'''\
|
|
# this should be simple
|
|
RepoType: git
|
|
Repo: https://git.host/repo.git
|
|
'''
|
|
)
|
|
)
|
|
srclib = fdroidserver.metadata.parse_yaml_srclib(Path('simple.yml'))
|
|
self.assertDictEqual(
|
|
{
|
|
'Repo': 'https://git.host/repo.git',
|
|
'RepoType': 'git',
|
|
'Subdir': None,
|
|
'Prepare': None,
|
|
},
|
|
srclib,
|
|
)
|
|
|
|
def test_parse_yaml_srclib_simple_with_blanks(self):
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
|
with Path('simple.yml').open('w', encoding='utf-8') as f:
|
|
f.write(
|
|
textwrap.dedent(
|
|
'''\
|
|
# this should be simple
|
|
|
|
RepoType: git
|
|
|
|
Repo: https://git.host/repo.git
|
|
|
|
Subdir:
|
|
|
|
Prepare:
|
|
'''
|
|
)
|
|
)
|
|
srclib = fdroidserver.metadata.parse_yaml_srclib(Path('simple.yml'))
|
|
self.assertDictEqual(
|
|
{
|
|
'Repo': 'https://git.host/repo.git',
|
|
'RepoType': 'git',
|
|
'Subdir': [''],
|
|
'Prepare': '',
|
|
},
|
|
srclib,
|
|
)
|
|
|
|
def test_parse_yaml_srclib_Changelog_cketti(self):
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
|
with Path('Changelog-cketti.yml').open('w', encoding='utf-8') as f:
|
|
f.write(
|
|
textwrap.dedent(
|
|
'''\
|
|
RepoType: git
|
|
Repo: https://github.com/cketti/ckChangeLog
|
|
|
|
Subdir: library,ckChangeLog/src/main
|
|
Prepare: "[ -f project.properties ] || echo 'source.dir=java' > ant.properties && echo -e 'android.library=true\\\\ntarget=android-19' > project.properties"
|
|
'''
|
|
)
|
|
)
|
|
srclib = fdroidserver.metadata.parse_yaml_srclib(
|
|
Path('Changelog-cketti.yml')
|
|
)
|
|
self.assertDictEqual(
|
|
srclib,
|
|
{
|
|
'Repo': 'https://github.com/cketti/ckChangeLog',
|
|
'RepoType': 'git',
|
|
'Subdir': ['library', 'ckChangeLog/src/main'],
|
|
'Prepare': "[ -f project.properties ] || echo 'source.dir=java' > "
|
|
"ant.properties && echo -e "
|
|
"'android.library=true\\ntarget=android-19' > project.properties",
|
|
},
|
|
)
|
|
|
|
def test_read_srclibs_yml_subdir_list(self):
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
fdroidserver.metadata.srclibs = None
|
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
|
Path('srclibs').mkdir()
|
|
with Path('srclibs/with-list.yml').open('w', encoding='utf-8') as f:
|
|
f.write(
|
|
textwrap.dedent(
|
|
'''\
|
|
# this should be simple
|
|
RepoType: git
|
|
Repo: https://git.host/repo.git
|
|
|
|
Subdir:
|
|
- This is your last chance.
|
|
- After this, there is no turning back.
|
|
- You take the blue pill—the story ends,
|
|
- you wake up in your bed
|
|
- and believe whatever you want to believe.
|
|
- You take the red pill—you stay in Wonderland
|
|
- and I show you how deep the rabbit-hole goes.
|
|
Prepare:
|
|
There is a difference between knowing the path
|
|
and walking the path.
|
|
'''
|
|
)
|
|
)
|
|
fdroidserver.metadata.read_srclibs()
|
|
self.maxDiff = None
|
|
self.assertDictEqual(
|
|
fdroidserver.metadata.srclibs,
|
|
{
|
|
'with-list': {
|
|
'RepoType': 'git',
|
|
'Repo': 'https://git.host/repo.git',
|
|
'Subdir': [
|
|
'This is your last chance.',
|
|
'After this, there is no turning back.',
|
|
'You take the blue pill—the story ends,',
|
|
'you wake up in your bed',
|
|
'and believe whatever you want to believe.',
|
|
'You take the red pill—you stay in Wonderland',
|
|
'and I show you how deep the rabbit-hole goes.',
|
|
],
|
|
'Prepare': 'There is a difference between knowing the path '
|
|
'and walking the path.',
|
|
}
|
|
},
|
|
)
|
|
|
|
def test_read_srclibs_yml_prepare_list(self):
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
fdroidserver.metadata.srclibs = None
|
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
|
Path('srclibs').mkdir()
|
|
with Path('srclibs/with-list.yml').open('w', encoding='utf-8') as f:
|
|
f.write(
|
|
textwrap.dedent(
|
|
'''\
|
|
# this should be simple
|
|
RepoType: git
|
|
Repo: https://git.host/repo.git
|
|
|
|
Subdir:
|
|
Prepare:
|
|
- The Matrix is a system, Neo.
|
|
- That system is our enemy.
|
|
- But when you're inside, you look around, what do you see?
|
|
- Businessmen, teachers, lawyers, carpenters.
|
|
- The very minds of the people we are trying to save.
|
|
- But until we do, these people are still a part of that system and that makes them our enemy.
|
|
- You have to understand, most of these people are not ready to be unplugged.
|
|
- And many of them are so inert, so hopelessly dependent on the system that they will fight to protect it.
|
|
'''
|
|
)
|
|
)
|
|
fdroidserver.metadata.read_srclibs()
|
|
self.maxDiff = None
|
|
self.assertDictEqual(
|
|
fdroidserver.metadata.srclibs,
|
|
{
|
|
'with-list': {
|
|
'RepoType': 'git',
|
|
'Repo': 'https://git.host/repo.git',
|
|
'Subdir': [''],
|
|
'Prepare': 'The Matrix is a system, Neo. && '
|
|
'That system is our enemy. && '
|
|
'But when you\'re inside, you look around, what do you see? && '
|
|
'Businessmen, teachers, lawyers, carpenters. && '
|
|
'The very minds of the people we are trying to save. && '
|
|
'But until we do, these people are still a part of that system and that makes them our enemy. && '
|
|
'You have to understand, most of these people are not ready to be unplugged. && '
|
|
'And many of them are so inert, so hopelessly dependent on the system that they will fight to protect it.',
|
|
}
|
|
},
|
|
)
|
|
|
|
def test_read_srclibs(self):
|
|
fdroidserver.metadata.warnings_action = 'error'
|
|
fdroidserver.metadata.srclibs = None
|
|
with tempfile.TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
|
|
Path('srclibs').mkdir()
|
|
with Path('srclibs/simple.yml').open('w', encoding='utf-8') as f:
|
|
f.write(
|
|
textwrap.dedent(
|
|
'''\
|
|
RepoType: git
|
|
Repo: https://git.host/repo.git
|
|
'''
|
|
)
|
|
)
|
|
with Path('srclibs/simple-wb.yml').open('w', encoding='utf-8') as f:
|
|
f.write(
|
|
textwrap.dedent(
|
|
'''\
|
|
# this should be simple
|
|
RepoType: git
|
|
Repo: https://git.host/repo.git
|
|
|
|
Subdir:
|
|
Prepare:
|
|
'''
|
|
)
|
|
)
|
|
fdroidserver.metadata.read_srclibs()
|
|
self.assertDictEqual(
|
|
fdroidserver.metadata.srclibs,
|
|
{
|
|
'simple-wb': {
|
|
'RepoType': 'git',
|
|
'Repo': 'https://git.host/repo.git',
|
|
'Subdir': [''],
|
|
'Prepare': '',
|
|
},
|
|
'simple': {
|
|
'RepoType': 'git',
|
|
'Repo': 'https://git.host/repo.git',
|
|
'Subdir': None,
|
|
'Prepare': None,
|
|
},
|
|
},
|
|
)
|
|
|
|
def test_build_ndk_path(self):
|
|
""""""
|
|
config = {'ndk_paths': {}, 'sdk_path': tempfile.mkdtemp(prefix='android-sdk-')}
|
|
fdroidserver.common.config = config
|
|
|
|
build = fdroidserver.metadata.Build()
|
|
build.ndk = 'r10e'
|
|
self.assertEqual('', build.ndk_path())
|
|
|
|
correct = '/fake/path/ndk/r21b'
|
|
config['ndk_paths'] = {'r21b': correct}
|
|
self.assertEqual('', build.ndk_path())
|
|
config['ndk_paths'] = {'r10e': correct}
|
|
self.assertEqual(correct, build.ndk_path())
|
|
|
|
r10e = '/fake/path/ndk/r10e'
|
|
r22b = '/fake/path/ndk/r22e'
|
|
config['ndk_paths'] = {'r10e': r10e, 'r22b': r22b}
|
|
self.assertEqual(r10e, build.ndk_path())
|
|
|
|
build.ndk = ['r10e', 'r22b']
|
|
self.assertEqual(r10e, build.ndk_path())
|
|
|
|
build.ndk = ['r22b', 'r10e']
|
|
self.assertEqual(r22b, build.ndk_path())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = optparse.OptionParser()
|
|
parser.add_option(
|
|
"-v",
|
|
"--verbose",
|
|
action="store_true",
|
|
default=False,
|
|
help="Spew out even more information than normal",
|
|
)
|
|
(fdroidserver.common.options, args) = parser.parse_args(['--verbose'])
|
|
|
|
newSuite = unittest.TestSuite()
|
|
newSuite.addTest(unittest.makeSuite(MetadataTest))
|
|
unittest.main(failfast=True)
|