chiark / gitweb /
Merge branch 'pre-0.103-alpha4-rename' into 'master'
[fdroidserver.git] / tests / update.TestCase
1 #!/usr/bin/env python3
2
3 # http://www.drdobbs.com/testing/unit-testing-with-python/240165163
4
5 import git
6 import inspect
7 import logging
8 import optparse
9 import os
10 import shutil
11 import sys
12 import tempfile
13 import unittest
14 import yaml
15 from binascii import unhexlify
16
17 localmodule = os.path.realpath(
18     os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..'))
19 print('localmodule: ' + localmodule)
20 if localmodule not in sys.path:
21     sys.path.insert(0, localmodule)
22
23 import fdroidserver.common
24 import fdroidserver.metadata
25 import fdroidserver.update
26 from fdroidserver.common import FDroidPopen
27
28
29 class UpdateTest(unittest.TestCase):
30     '''fdroid update'''
31
32     def testInsertStoreMetadata(self):
33         config = dict()
34         fdroidserver.common.fill_config_defaults(config)
35         config['accepted_formats'] = ('txt', 'yml')
36         fdroidserver.update.config = config
37         fdroidserver.update.options = fdroidserver.common.options
38         os.chdir(os.path.join(localmodule, 'tests'))
39
40         apps = dict()
41         for packageName in ('info.guardianproject.urzip', 'org.videolan.vlc', 'obb.mainpatch.current'):
42             apps[packageName] = dict()
43             apps[packageName]['id'] = packageName
44             apps[packageName]['CurrentVersionCode'] = 0xcafebeef
45         apps['info.guardianproject.urzip']['CurrentVersionCode'] = 100
46         fdroidserver.update.insert_localized_app_metadata(apps)
47
48         self.assertEqual(3, len(apps))
49         for packageName, app in apps.items():
50             self.assertTrue('localized' in app)
51             self.assertTrue('en-US' in app['localized'])
52             self.assertEqual(1, len(app['localized']))
53             if packageName == 'info.guardianproject.urzip':
54                 self.assertEqual(5, len(app['localized']['en-US']))
55                 self.assertEqual('full description\n', app['localized']['en-US']['description'])
56                 self.assertEqual('title\n', app['localized']['en-US']['name'])
57                 self.assertEqual('short description\n', app['localized']['en-US']['summary'])
58                 self.assertEqual('video\n', app['localized']['en-US']['video'])
59                 self.assertEqual('100\n', app['localized']['en-US']['whatsNew'])
60             elif packageName == 'org.videolan.vlc':
61                 self.assertEqual('icon.png', app['localized']['en-US']['icon'])
62                 self.assertEqual(9, len(app['localized']['en-US']['phoneScreenshots']))
63                 self.assertEqual(15, len(app['localized']['en-US']['sevenInchScreenshots']))
64             elif packageName == 'obb.mainpatch.current':
65                 self.assertEqual('icon.png', app['localized']['en-US']['icon'])
66                 self.assertEqual('featureGraphic.png', app['localized']['en-US']['featureGraphic'])
67                 self.assertEqual(1, len(app['localized']['en-US']['phoneScreenshots']))
68                 self.assertEqual(1, len(app['localized']['en-US']['sevenInchScreenshots']))
69
70     def test_insert_triple_t_metadata(self):
71         importer = os.path.join(localmodule, 'tests', 'tmp', 'importer')
72         packageName = 'org.fdroid.ci.test.app'
73         if not os.path.isdir(importer):
74             logging.warning('skipping test_insert_triple_t_metadata, import.TestCase must run first!')
75             return
76         tmpdir = os.path.join(localmodule, '.testfiles')
77         if not os.path.exists(tmpdir):
78             os.makedirs(tmpdir)
79         tmptestsdir = tempfile.mkdtemp(prefix='test_insert_triple_t_metadata-', dir=tmpdir)
80         packageDir = os.path.join(tmptestsdir, 'build', packageName)
81         shutil.copytree(importer, packageDir)
82
83         # always use the same commit so these tests work when ci-test-app.git is updated
84         repo = git.Repo(packageDir)
85         for remote in repo.remotes:
86             remote.fetch()
87         repo.git.reset('--hard', 'b9e5d1a0d8d6fc31d4674b2f0514fef10762ed4f')
88         repo.git.clean('-fdx')
89
90         os.mkdir(os.path.join(tmptestsdir, 'metadata'))
91         metadata = dict()
92         metadata['Description'] = 'This is just a test app'
93         with open(os.path.join(tmptestsdir, 'metadata', packageName + '.yml'), 'w') as fp:
94             yaml.dump(metadata, fp)
95
96         config = dict()
97         fdroidserver.common.fill_config_defaults(config)
98         config['accepted_formats'] = ('yml')
99         fdroidserver.common.config = config
100         fdroidserver.update.config = config
101         fdroidserver.update.options = fdroidserver.common.options
102         os.chdir(tmptestsdir)
103
104         apps = fdroidserver.metadata.read_metadata(xref=True)
105         fdroidserver.update.copy_triple_t_store_metadata(apps)
106
107         # TODO ideally, this would compare the whole dict like in metadata.TestCase's test_read_metadata()
108         correctlocales = [
109             'ar', 'ast_ES', 'az', 'ca', 'ca_ES', 'cs-CZ', 'cs_CZ', 'da',
110             'da-DK', 'de', 'de-DE', 'el', 'en-US', 'es', 'es-ES', 'es_ES', 'et',
111             'fi', 'fr', 'fr-FR', 'he_IL', 'hi-IN', 'hi_IN', 'hu', 'id', 'it',
112             'it-IT', 'it_IT', 'iw-IL', 'ja', 'ja-JP', 'kn_IN', 'ko', 'ko-KR',
113             'ko_KR', 'lt', 'nb', 'nb_NO', 'nl', 'nl-NL', 'no', 'pl', 'pl-PL',
114             'pl_PL', 'pt', 'pt-BR', 'pt-PT', 'pt_BR', 'ro', 'ro_RO', 'ru-RU',
115             'ru_RU', 'sv-SE', 'sv_SE', 'te', 'tr', 'tr-TR', 'uk', 'uk_UA', 'vi',
116             'vi_VN', 'zh-CN', 'zh_CN', 'zh_TW',
117         ]
118         locales = sorted(list(apps['org.fdroid.ci.test.app']['localized'].keys()))
119         self.assertEqual(correctlocales, locales)
120
121     def javagetsig(self, apkfile):
122         getsig_dir = os.path.join(os.path.dirname(__file__), 'getsig')
123         if not os.path.exists(getsig_dir + "/getsig.class"):
124             logging.critical("getsig.class not found. To fix: cd '%s' && ./make.sh" % getsig_dir)
125             sys.exit(1)
126         # FDroidPopen needs some config to work
127         config = dict()
128         fdroidserver.common.fill_config_defaults(config)
129         fdroidserver.common.config = config
130         p = FDroidPopen(['java', '-cp', os.path.join(os.path.dirname(__file__), 'getsig'),
131                          'getsig', os.path.join(os.getcwd(), apkfile)])
132         sig = None
133         for line in p.output.splitlines():
134             if line.startswith('Result:'):
135                 sig = line[7:].strip()
136                 break
137         if p.returncode == 0:
138             return sig
139         else:
140             return None
141
142     def testGoodGetsig(self):
143         # config needed to use jarsigner and keytool
144         config = dict()
145         fdroidserver.common.fill_config_defaults(config)
146         fdroidserver.update.config = config
147         apkfile = os.path.join(os.path.dirname(__file__), 'urzip.apk')
148         sig = self.javagetsig(apkfile)
149         self.assertIsNotNone(sig, "sig is None")
150         pysig = fdroidserver.update.getsig(apkfile)
151         self.assertIsNotNone(pysig, "pysig is None")
152         self.assertEqual(sig, fdroidserver.update.getsig(apkfile),
153                          "python sig not equal to java sig!")
154         self.assertEqual(len(sig), len(pysig),
155                          "the length of the two sigs are different!")
156         try:
157             self.assertEqual(unhexlify(sig), unhexlify(pysig),
158                              "the length of the two sigs are different!")
159         except TypeError as e:
160             print(e)
161             self.assertTrue(False, 'TypeError!')
162
163     def testBadGetsig(self):
164         # config needed to use jarsigner and keytool
165         config = dict()
166         fdroidserver.common.fill_config_defaults(config)
167         fdroidserver.update.config = config
168         apkfile = os.path.join(os.path.dirname(__file__), 'urzip-badsig.apk')
169         sig = self.javagetsig(apkfile)
170         self.assertIsNone(sig, "sig should be None: " + str(sig))
171         pysig = fdroidserver.update.getsig(apkfile)
172         self.assertIsNone(pysig, "python sig should be None: " + str(sig))
173
174         apkfile = os.path.join(os.path.dirname(__file__), 'urzip-badcert.apk')
175         sig = self.javagetsig(apkfile)
176         self.assertIsNone(sig, "sig should be None: " + str(sig))
177         pysig = fdroidserver.update.getsig(apkfile)
178         self.assertIsNone(pysig, "python sig should be None: " + str(sig))
179
180     def testScanApksAndObbs(self):
181         os.chdir(os.path.join(localmodule, 'tests'))
182         if os.path.basename(os.getcwd()) != 'tests':
183             raise Exception('This test must be run in the "tests/" subdir')
184
185         config = dict()
186         fdroidserver.common.fill_config_defaults(config)
187         config['ndk_paths'] = dict()
188         config['accepted_formats'] = ['json', 'txt', 'yml']
189         fdroidserver.common.config = config
190         fdroidserver.update.config = config
191
192         fdroidserver.update.options = type('', (), {})()
193         fdroidserver.update.options.clean = True
194         fdroidserver.update.options.delete_unknown = True
195
196         apps = fdroidserver.metadata.read_metadata(xref=True)
197         knownapks = fdroidserver.common.KnownApks()
198         apks, cachechanged = fdroidserver.update.scan_apks({}, 'repo', knownapks, False)
199         self.assertEqual(len(apks), 6)
200         apk = apks[0]
201         self.assertEqual(apk['minSdkVersion'], '4')
202         self.assertEqual(apk['targetSdkVersion'], '18')
203         self.assertFalse('maxSdkVersion' in apk)
204
205         fdroidserver.update.insert_obbs('repo', apps, apks)
206         for apk in apks:
207             if apk['packageName'] == 'obb.mainpatch.current':
208                 self.assertEqual(apk.get('obbMainFile'), 'main.1619.obb.mainpatch.current.obb')
209                 self.assertEqual(apk.get('obbPatchFile'), 'patch.1619.obb.mainpatch.current.obb')
210             elif apk['packageName'] == 'obb.main.oldversion':
211                 self.assertEqual(apk.get('obbMainFile'), 'main.1434483388.obb.main.oldversion.obb')
212                 self.assertIsNone(apk.get('obbPatchFile'))
213             elif apk['packageName'] == 'obb.main.twoversions':
214                 self.assertIsNone(apk.get('obbPatchFile'))
215                 if apk['versionCode'] == 1101613:
216                     self.assertEqual(apk.get('obbMainFile'), 'main.1101613.obb.main.twoversions.obb')
217                 elif apk['versionCode'] == 1101615:
218                     self.assertEqual(apk.get('obbMainFile'), 'main.1101615.obb.main.twoversions.obb')
219                 elif apk['versionCode'] == 1101617:
220                     self.assertEqual(apk.get('obbMainFile'), 'main.1101615.obb.main.twoversions.obb')
221                 else:
222                     self.assertTrue(False)
223             elif apk['packageName'] == 'info.guardianproject.urzip':
224                 self.assertIsNone(apk.get('obbMainFile'))
225                 self.assertIsNone(apk.get('obbPatchFile'))
226
227     def test_scan_invalid_apk(self):
228         os.chdir(os.path.join(localmodule, 'tests'))
229         if os.path.basename(os.getcwd()) != 'tests':
230             raise Exception('This test must be run in the "tests/" subdir')
231
232         config = dict()
233         fdroidserver.common.fill_config_defaults(config)
234         fdroidserver.common.config = config
235         fdroidserver.update.config = config
236         fdroidserver.update.options.delete_unknown = False
237
238         knownapks = fdroidserver.common.KnownApks()
239         apk = 'fake.ota.update_1234.zip'  # this is not an APK, scanning should fail
240         (skip, apk, cachechanged) = fdroidserver.update.scan_apk({}, apk, 'repo', knownapks, False)
241
242         self.assertTrue(skip)
243         self.assertIsNone(apk)
244         self.assertFalse(cachechanged)
245
246
247 if __name__ == "__main__":
248     parser = optparse.OptionParser()
249     parser.add_option("-v", "--verbose", action="store_true", default=False,
250                       help="Spew out even more information than normal")
251     (fdroidserver.common.options, args) = parser.parse_args(['--verbose'])
252
253     newSuite = unittest.TestSuite()
254     newSuite.addTest(unittest.makeSuite(UpdateTest))
255     unittest.main()