2016-01-04 21:17:58 +01:00
|
|
|
#!/usr/bin/env python3
|
2015-07-22 10:16:43 +02:00
|
|
|
|
|
|
|
# http://www.drdobbs.com/testing/unit-testing-with-python/240165163
|
|
|
|
|
2018-08-08 00:59:25 +02:00
|
|
|
import io
|
2017-11-29 22:03:26 +01:00
|
|
|
import glob
|
2015-07-22 10:16:43 +02:00
|
|
|
import inspect
|
2017-11-30 10:14:38 +01:00
|
|
|
import logging
|
2015-07-22 10:16:43 +02:00
|
|
|
import optparse
|
|
|
|
import os
|
2017-11-29 22:03:26 +01:00
|
|
|
import random
|
|
|
|
import shutil
|
2015-07-22 10:16:43 +02:00
|
|
|
import sys
|
|
|
|
import unittest
|
2016-11-23 15:14:44 +01:00
|
|
|
import yaml
|
2017-05-09 14:13:14 +02:00
|
|
|
import tempfile
|
2018-08-08 00:59:25 +02:00
|
|
|
import textwrap
|
|
|
|
from unittest import mock
|
2015-07-22 10:16:43 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
import fdroidserver.common
|
|
|
|
import fdroidserver.metadata
|
2018-08-08 00:59:25 +02:00
|
|
|
from fdroidserver.exception import MetaDataException
|
2015-07-22 10:16:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
class MetadataTest(unittest.TestCase):
|
|
|
|
'''fdroidserver/metadata.py'''
|
|
|
|
|
2017-11-30 10:14:38 +01:00
|
|
|
def setUp(self):
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
self.basedir = os.path.join(localmodule, 'tests')
|
|
|
|
self.tmpdir = os.path.abspath(os.path.join(self.basedir, '..', '.testfiles'))
|
|
|
|
if not os.path.exists(self.tmpdir):
|
|
|
|
os.makedirs(self.tmpdir)
|
|
|
|
os.chdir(self.basedir)
|
|
|
|
|
2015-07-22 10:16:43 +02:00
|
|
|
def test_read_metadata(self):
|
convert metadata.Build to a subclass of dict
Like with the App class in the commit before, this makes it a lot
easier to work with this data when converting between the internal
formats and external formats like YAML, JSON, MsgPack, protobuf, etc.
The one unfortunate thing here is Build.update. It becomes
dict.update(), which is a method not an attribute.
build.get('update') or build['update'] could be used, but that would
be oddly inconsistent. So instead the field is renamed to
'androidupdate', except for in the .txt v0 metadata files. This better
describes what field does anyway, since it runs `android update`.
Build.update is only referenced in two places right next to each other
for the ant builds, so this change still seems worthwhile.
2016-11-29 13:26:32 +01:00
|
|
|
|
|
|
|
def _build_yaml_representer(dumper, data):
|
|
|
|
'''Creates a YAML representation of a Build instance'''
|
|
|
|
return dumper.represent_dict(data)
|
|
|
|
|
2015-07-22 10:16:43 +02:00
|
|
|
self.maxDiff = None
|
|
|
|
|
2015-08-27 11:43:17 +02:00
|
|
|
# these need to be set to prevent code running on None, only
|
|
|
|
# 'accepted_formats' is actually used in metadata.py
|
2015-07-22 10:16:43 +02:00
|
|
|
config = dict()
|
|
|
|
config['sdk_path'] = '/opt/android-sdk'
|
|
|
|
config['ndk_paths'] = dict()
|
2016-11-23 15:01:23 +01:00
|
|
|
config['accepted_formats'] = ['json', 'txt', 'yml']
|
2015-07-22 10:16:43 +02:00
|
|
|
fdroidserver.common.config = config
|
|
|
|
|
|
|
|
apps = fdroidserver.metadata.read_metadata(xref=True)
|
2017-06-27 23:55:38 +02:00
|
|
|
for appid in ('org.smssecure.smssecure', 'org.adaway',
|
|
|
|
'org.videolan.vlc', 'com.politedroid'):
|
2016-11-23 15:14:44 +01:00
|
|
|
savepath = os.path.join('metadata', 'dump', appid + '.yaml')
|
2016-11-23 17:25:59 +01:00
|
|
|
frommeta = dict(apps[appid])
|
2015-11-28 13:09:47 +01:00
|
|
|
self.assertTrue(appid in apps)
|
2016-11-23 15:14:44 +01:00
|
|
|
with open(savepath, 'r') as f:
|
|
|
|
frompickle = yaml.load(f)
|
2016-06-10 12:02:03 +02:00
|
|
|
self.assertEqual(frommeta, frompickle)
|
2017-06-27 23:55:38 +02:00
|
|
|
# comment above assert and uncomment below to update test
|
|
|
|
# files when new metadata fields are added
|
2016-11-23 15:14:44 +01:00
|
|
|
# with open(savepath, 'w') as f:
|
convert metadata.Build to a subclass of dict
Like with the App class in the commit before, this makes it a lot
easier to work with this data when converting between the internal
formats and external formats like YAML, JSON, MsgPack, protobuf, etc.
The one unfortunate thing here is Build.update. It becomes
dict.update(), which is a method not an attribute.
build.get('update') or build['update'] could be used, but that would
be oddly inconsistent. So instead the field is renamed to
'androidupdate', except for in the .txt v0 metadata files. This better
describes what field does anyway, since it runs `android update`.
Build.update is only referenced in two places right next to each other
for the ant builds, so this change still seems worthwhile.
2016-11-29 13:26:32 +01:00
|
|
|
# yaml.add_representer(fdroidserver.metadata.Build, _build_yaml_representer)
|
2016-11-23 15:14:44 +01:00
|
|
|
# yaml.dump(frommeta, f, default_flow_style=False)
|
2015-07-22 10:16:43 +02:00
|
|
|
|
2017-05-09 14:13:14 +02:00
|
|
|
def test_rewrite_yaml_fakeotaupdate(self):
|
2017-11-30 10:14:38 +01:00
|
|
|
testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
|
2017-05-09 14:13:14 +02:00
|
|
|
fdroidserver.common.config = {'accepted_formats': ['txt', 'yml']}
|
|
|
|
|
|
|
|
# rewrite metadata
|
|
|
|
allapps = fdroidserver.metadata.read_metadata(xref=True)
|
|
|
|
for appid, app in allapps.items():
|
|
|
|
if appid == 'fake.ota.update':
|
|
|
|
fdroidserver.metadata.write_metadata(os.path.join(testdir, appid + '.yml'), app)
|
|
|
|
|
|
|
|
# assert rewrite result
|
|
|
|
with open(os.path.join(testdir, 'fake.ota.update.yml'), 'r', encoding='utf-8') as result:
|
2017-07-04 13:35:05 +02:00
|
|
|
with open('metadata-rewrite-yml/fake.ota.update.yml', 'r', encoding='utf-8') as orig:
|
2017-05-09 14:13:14 +02:00
|
|
|
self.maxDiff = None
|
|
|
|
self.assertEqual(result.read(), orig.read())
|
|
|
|
|
|
|
|
def test_rewrite_yaml_fdroidclient(self):
|
2017-11-30 10:14:38 +01:00
|
|
|
testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
|
2017-05-09 14:13:14 +02:00
|
|
|
fdroidserver.common.config = {'accepted_formats': ['txt', 'yml']}
|
|
|
|
|
|
|
|
# rewrite metadata
|
|
|
|
allapps = fdroidserver.metadata.read_metadata(xref=True)
|
|
|
|
for appid, app in allapps.items():
|
|
|
|
if appid == 'org.fdroid.fdroid':
|
|
|
|
fdroidserver.metadata.write_metadata(os.path.join(testdir, appid + '.yml'), app)
|
|
|
|
|
|
|
|
# assert rewrite result
|
|
|
|
with open(os.path.join(testdir, 'org.fdroid.fdroid.yml'), 'r', encoding='utf-8') as result:
|
2017-07-04 13:35:05 +02:00
|
|
|
with open('metadata-rewrite-yml/org.fdroid.fdroid.yml', 'r', encoding='utf-8') as orig:
|
2017-05-09 14:13:14 +02:00
|
|
|
self.maxDiff = None
|
|
|
|
self.assertEqual(result.read(), orig.read())
|
|
|
|
|
|
|
|
def test_rewrite_yaml_special_build_params(self):
|
2017-11-30 10:14:38 +01:00
|
|
|
testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
|
2017-05-09 14:13:14 +02:00
|
|
|
fdroidserver.common.config = {'accepted_formats': ['txt', 'yml']}
|
|
|
|
|
|
|
|
# rewrite metadata
|
|
|
|
allapps = fdroidserver.metadata.read_metadata(xref=True)
|
|
|
|
for appid, app in allapps.items():
|
|
|
|
if appid == 'app.with.special.build.params':
|
|
|
|
fdroidserver.metadata.write_metadata(os.path.join(testdir, appid + '.yml'), app)
|
|
|
|
|
|
|
|
# assert rewrite result
|
|
|
|
with open(os.path.join(testdir, 'app.with.special.build.params.yml'), 'r', encoding='utf-8') as result:
|
2017-07-04 13:35:05 +02:00
|
|
|
with open('metadata-rewrite-yml/app.with.special.build.params.yml', 'r', encoding='utf-8') as orig:
|
2017-05-09 14:13:14 +02:00
|
|
|
self.maxDiff = None
|
|
|
|
self.assertEqual(result.read(), orig.read())
|
|
|
|
|
2017-11-29 22:03:26 +01:00
|
|
|
def test_read_metadata_sort_by_time(self):
|
2017-11-30 10:14:38 +01:00
|
|
|
testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir)
|
2017-11-29 22:03:26 +01:00
|
|
|
metadatadir = os.path.join(testdir, 'metadata')
|
|
|
|
os.makedirs(metadatadir)
|
|
|
|
fdroidserver.common.config = {'accepted_formats': ['txt']}
|
|
|
|
|
|
|
|
randomlist = []
|
2017-11-30 10:14:38 +01:00
|
|
|
randomapps = glob.glob(os.path.join(self.basedir, 'metadata', '*.txt'))
|
2017-11-29 22:03:26 +01:00
|
|
|
random.shuffle(randomapps)
|
|
|
|
i = 1
|
|
|
|
for f in randomapps:
|
|
|
|
shutil.copy(f, metadatadir)
|
|
|
|
new = os.path.join(metadatadir, os.path.basename(f))
|
|
|
|
stat = os.stat(new)
|
|
|
|
os.utime(new, (stat.st_ctime, stat.st_mtime + i))
|
|
|
|
# prepend new item so newest is always first
|
|
|
|
randomlist = [os.path.basename(f)[:-4]] + randomlist
|
|
|
|
i += 1
|
|
|
|
os.chdir(testdir)
|
|
|
|
allapps = fdroidserver.metadata.read_metadata(xref=True, sort_by_time=True)
|
|
|
|
allappids = []
|
|
|
|
for appid, app in allapps.items():
|
|
|
|
allappids.append(appid)
|
|
|
|
self.assertEqual(randomlist, allappids)
|
|
|
|
|
2018-08-08 00:59:25 +02:00
|
|
|
def test_parse_yaml_metadata_unknown_app_field(self):
|
|
|
|
mf = io.StringIO(textwrap.dedent("""\
|
|
|
|
AutoName: F-Droid
|
|
|
|
RepoType: git
|
|
|
|
Builds: []
|
|
|
|
bad: value"""))
|
2018-08-08 02:18:19 +02:00
|
|
|
mf.name = 'mock_filename.yaml'
|
2018-08-08 00:59:25 +02:00
|
|
|
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"""))
|
2018-08-08 02:18:19 +02:00
|
|
|
mf.name = 'mock_filename.yaml'
|
2018-08-08 00:59:25 +02:00
|
|
|
with mock.patch('fdroidserver.metadata.warnings_action', 'error'):
|
|
|
|
with self.assertRaises(MetaDataException):
|
|
|
|
fdroidserver.metadata.parse_yaml_metadata(mf, {})
|
|
|
|
|
2015-07-22 10:16:43 +02:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2018-08-14 10:34:13 +02:00
|
|
|
os.chdir(os.path.dirname(__file__))
|
|
|
|
|
2015-07-22 10:16:43 +02:00
|
|
|
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))
|
2017-10-20 11:51:59 +02:00
|
|
|
unittest.main(failfast=False)
|