3 # http://www.drdobbs.com/testing/unit-testing-with-python/240165163
16 from binascii import unhexlify
17 from distutils.version import LooseVersion
19 localmodule = os.path.realpath(
20 os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..'))
21 print('localmodule: ' + localmodule)
22 if localmodule not in sys.path:
23 sys.path.insert(0, localmodule)
25 import fdroidserver.common
26 import fdroidserver.exception
27 import fdroidserver.metadata
28 import fdroidserver.update
29 from fdroidserver.common import FDroidPopen
32 class UpdateTest(unittest.TestCase):
36 logging.basicConfig(level=logging.INFO)
37 self.basedir = os.path.join(localmodule, 'tests')
38 self.tmpdir = os.path.abspath(os.path.join(self.basedir, '..', '.testfiles'))
39 if not os.path.exists(self.tmpdir):
40 os.makedirs(self.tmpdir)
41 os.chdir(self.basedir)
43 def testInsertStoreMetadata(self):
45 fdroidserver.common.fill_config_defaults(config)
46 config['accepted_formats'] = ('txt', 'yml')
47 fdroidserver.update.config = config
48 fdroidserver.update.options = fdroidserver.common.options
49 os.chdir(os.path.join(localmodule, 'tests'))
51 shutil.rmtree(os.path.join('repo', 'info.guardianproject.urzip'), ignore_errors=True)
53 shutil.rmtree(os.path.join('build', 'com.nextcloud.client'), ignore_errors=True)
54 shutil.copytree(os.path.join('source-files', 'com.nextcloud.client'),
55 os.path.join('build', 'com.nextcloud.client'))
57 shutil.rmtree(os.path.join('build', 'com.nextcloud.client.dev'), ignore_errors=True)
58 shutil.copytree(os.path.join('source-files', 'com.nextcloud.client.dev'),
59 os.path.join('build', 'com.nextcloud.client.dev'))
61 shutil.rmtree(os.path.join('build', 'eu.siacs.conversations'), ignore_errors=True)
62 shutil.copytree(os.path.join('source-files', 'eu.siacs.conversations'),
63 os.path.join('build', 'eu.siacs.conversations'))
66 for packageName in ('info.guardianproject.urzip', 'org.videolan.vlc', 'obb.mainpatch.current',
67 'com.nextcloud.client', 'com.nextcloud.client.dev',
68 'eu.siacs.conversations'):
69 apps[packageName] = fdroidserver.metadata.App()
70 apps[packageName]['id'] = packageName
71 apps[packageName]['CurrentVersionCode'] = 0xcafebeef
73 apps['info.guardianproject.urzip']['CurrentVersionCode'] = 100
75 buildnextcloudclient = fdroidserver.metadata.Build()
76 buildnextcloudclient.gradle = ['generic']
77 apps['com.nextcloud.client']['builds'] = [buildnextcloudclient]
79 buildnextclouddevclient = fdroidserver.metadata.Build()
80 buildnextclouddevclient.gradle = ['versionDev']
81 apps['com.nextcloud.client.dev']['builds'] = [buildnextclouddevclient]
83 build_conversations = fdroidserver.metadata.Build()
84 build_conversations.gradle = ['free']
85 apps['eu.siacs.conversations']['builds'] = [build_conversations]
87 fdroidserver.update.insert_localized_app_metadata(apps)
89 appdir = os.path.join('repo', 'info.guardianproject.urzip', 'en-US')
90 self.assertTrue(os.path.isfile(os.path.join(appdir, 'icon.png')))
91 self.assertTrue(os.path.isfile(os.path.join(appdir, 'featureGraphic.png')))
93 self.assertEqual(6, len(apps))
94 for packageName, app in apps.items():
95 self.assertTrue('localized' in app)
96 self.assertTrue('en-US' in app['localized'])
97 self.assertEqual(1, len(app['localized']))
98 if packageName == 'info.guardianproject.urzip':
99 self.assertEqual(7, len(app['localized']['en-US']))
100 self.assertEqual('full description\n', app['localized']['en-US']['description'])
101 self.assertEqual('title\n', app['localized']['en-US']['name'])
102 self.assertEqual('short description\n', app['localized']['en-US']['summary'])
103 self.assertEqual('video\n', app['localized']['en-US']['video'])
104 self.assertEqual('icon.png', app['localized']['en-US']['icon'])
105 self.assertEqual('featureGraphic.png', app['localized']['en-US']['featureGraphic'])
106 self.assertEqual('100\n', app['localized']['en-US']['whatsNew'])
107 elif packageName == 'org.videolan.vlc':
108 self.assertEqual('icon.png', app['localized']['en-US']['icon'])
109 self.assertEqual(9, len(app['localized']['en-US']['phoneScreenshots']))
110 self.assertEqual(15, len(app['localized']['en-US']['sevenInchScreenshots']))
111 elif packageName == 'obb.mainpatch.current':
112 self.assertEqual('icon.png', app['localized']['en-US']['icon'])
113 self.assertEqual('featureGraphic.png', app['localized']['en-US']['featureGraphic'])
114 self.assertEqual(1, len(app['localized']['en-US']['phoneScreenshots']))
115 self.assertEqual(1, len(app['localized']['en-US']['sevenInchScreenshots']))
116 elif packageName == 'com.nextcloud.client':
117 self.assertEqual('Nextcloud', app['localized']['en-US']['name'])
118 self.assertEqual(1073, len(app['localized']['en-US']['description']))
119 self.assertEqual(78, len(app['localized']['en-US']['summary']))
120 elif packageName == 'com.nextcloud.client.dev':
121 self.assertEqual('Nextcloud Dev', app['localized']['en-US']['name'])
122 self.assertEqual(586, len(app['localized']['en-US']['description']))
123 self.assertEqual(79, len(app['localized']['en-US']['summary']))
124 elif packageName == 'eu.siacs.conversations':
125 self.assertEqual('Conversations', app['localized']['en-US']['name'])
127 def test_insert_triple_t_metadata(self):
128 importer = os.path.join(self.basedir, 'tmp', 'importer')
129 packageName = 'org.fdroid.ci.test.app'
130 if not os.path.isdir(importer):
131 logging.warning('skipping test_insert_triple_t_metadata, import.TestCase must run first!')
133 tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
135 packageDir = os.path.join(tmptestsdir, 'build', packageName)
136 shutil.copytree(importer, packageDir)
138 # always use the same commit so these tests work when ci-test-app.git is updated
139 repo = git.Repo(packageDir)
140 for remote in repo.remotes:
142 repo.git.reset('--hard', 'b9e5d1a0d8d6fc31d4674b2f0514fef10762ed4f')
143 repo.git.clean('-fdx')
145 os.mkdir(os.path.join(tmptestsdir, 'metadata'))
147 metadata['Description'] = 'This is just a test app'
148 with open(os.path.join(tmptestsdir, 'metadata', packageName + '.yml'), 'w') as fp:
149 yaml.dump(metadata, fp)
152 fdroidserver.common.fill_config_defaults(config)
153 config['accepted_formats'] = ('yml')
154 fdroidserver.common.config = config
155 fdroidserver.update.config = config
156 fdroidserver.update.options = fdroidserver.common.options
157 os.chdir(tmptestsdir)
159 apps = fdroidserver.metadata.read_metadata(xref=True)
160 fdroidserver.update.copy_triple_t_store_metadata(apps)
162 # TODO ideally, this would compare the whole dict like in metadata.TestCase's test_read_metadata()
164 'ar', 'ast_ES', 'az', 'ca', 'ca_ES', 'cs-CZ', 'cs_CZ', 'da',
165 'da-DK', 'de', 'de-DE', 'el', 'en-US', 'es', 'es-ES', 'es_ES', 'et',
166 'fi', 'fr', 'fr-FR', 'he_IL', 'hi-IN', 'hi_IN', 'hu', 'id', 'it',
167 'it-IT', 'it_IT', 'iw-IL', 'ja', 'ja-JP', 'kn_IN', 'ko', 'ko-KR',
168 'ko_KR', 'lt', 'nb', 'nb_NO', 'nl', 'nl-NL', 'no', 'pl', 'pl-PL',
169 'pl_PL', 'pt', 'pt-BR', 'pt-PT', 'pt_BR', 'ro', 'ro_RO', 'ru-RU',
170 'ru_RU', 'sv-SE', 'sv_SE', 'te', 'tr', 'tr-TR', 'uk', 'uk_UA', 'vi',
171 'vi_VN', 'zh-CN', 'zh_CN', 'zh_TW',
173 locales = sorted(list(apps['org.fdroid.ci.test.app']['localized'].keys()))
174 self.assertEqual(correctlocales, locales)
176 def javagetsig(self, apkfile):
177 getsig_dir = os.path.join(os.path.dirname(__file__), 'getsig')
178 if not os.path.exists(getsig_dir + "/getsig.class"):
179 logging.critical("getsig.class not found. To fix: cd '%s' && ./make.sh" % getsig_dir)
181 # FDroidPopen needs some config to work
183 fdroidserver.common.fill_config_defaults(config)
184 fdroidserver.common.config = config
185 p = FDroidPopen(['java', '-cp', os.path.join(os.path.dirname(__file__), 'getsig'),
186 'getsig', os.path.join(os.getcwd(), apkfile)])
188 for line in p.output.splitlines():
189 if line.startswith('Result:'):
190 sig = line[7:].strip()
192 if p.returncode == 0:
197 def testGoodGetsig(self):
198 # config needed to use jarsigner and keytool
200 fdroidserver.common.fill_config_defaults(config)
201 fdroidserver.update.config = config
202 apkfile = os.path.join(os.path.dirname(__file__), 'urzip.apk')
203 sig = self.javagetsig(apkfile)
204 self.assertIsNotNone(sig, "sig is None")
205 pysig = fdroidserver.update.getsig(apkfile)
206 self.assertIsNotNone(pysig, "pysig is None")
207 self.assertEqual(sig, fdroidserver.update.getsig(apkfile),
208 "python sig not equal to java sig!")
209 self.assertEqual(len(sig), len(pysig),
210 "the length of the two sigs are different!")
212 self.assertEqual(unhexlify(sig), unhexlify(pysig),
213 "the length of the two sigs are different!")
214 except TypeError as e:
216 self.assertTrue(False, 'TypeError!')
218 def testBadGetsig(self):
219 """getsig() should still be able to fetch the fingerprint of bad signatures"""
220 # config needed to use jarsigner and keytool
222 fdroidserver.common.fill_config_defaults(config)
223 fdroidserver.update.config = config
225 apkfile = os.path.join(os.path.dirname(__file__), 'urzip-badsig.apk')
226 sig = fdroidserver.update.getsig(apkfile)
227 self.assertEqual(sig, 'e0ecb5fc2d63088e4a07ae410a127722',
228 "python sig should be: " + str(sig))
230 apkfile = os.path.join(os.path.dirname(__file__), 'urzip-badcert.apk')
231 sig = fdroidserver.update.getsig(apkfile)
232 self.assertEqual(sig, 'e0ecb5fc2d63088e4a07ae410a127722',
233 "python sig should be: " + str(sig))
235 def testScanApksAndObbs(self):
236 os.chdir(os.path.join(localmodule, 'tests'))
237 if os.path.basename(os.getcwd()) != 'tests':
238 raise Exception('This test must be run in the "tests/" subdir')
241 fdroidserver.common.fill_config_defaults(config)
242 config['ndk_paths'] = dict()
243 config['accepted_formats'] = ['json', 'txt', 'yml']
244 fdroidserver.common.config = config
245 fdroidserver.update.config = config
247 fdroidserver.update.options = type('', (), {})()
248 fdroidserver.update.options.clean = True
249 fdroidserver.update.options.delete_unknown = True
250 fdroidserver.update.options.rename_apks = False
251 fdroidserver.update.options.allow_disabled_algorithms = False
253 apps = fdroidserver.metadata.read_metadata(xref=True)
254 knownapks = fdroidserver.common.KnownApks()
255 apks, cachechanged = fdroidserver.update.process_apks({}, 'repo', knownapks, False)
256 self.assertEqual(len(apks), 14)
258 self.assertEqual(apk['packageName'], 'com.politedroid')
259 self.assertEqual(apk['versionCode'], 3)
260 self.assertEqual(apk['minSdkVersion'], '3')
261 self.assertEqual(apk['targetSdkVersion'], '3')
262 self.assertFalse('maxSdkVersion' in apk)
264 self.assertEqual(apk['packageName'], 'obb.main.oldversion')
265 self.assertEqual(apk['versionCode'], 1444412523)
266 self.assertEqual(apk['minSdkVersion'], '4')
267 self.assertEqual(apk['targetSdkVersion'], '18')
268 self.assertFalse('maxSdkVersion' in apk)
270 fdroidserver.update.insert_obbs('repo', apps, apks)
272 if apk['packageName'] == 'obb.mainpatch.current':
273 self.assertEqual(apk.get('obbMainFile'), 'main.1619.obb.mainpatch.current.obb')
274 self.assertEqual(apk.get('obbPatchFile'), 'patch.1619.obb.mainpatch.current.obb')
275 elif apk['packageName'] == 'obb.main.oldversion':
276 self.assertEqual(apk.get('obbMainFile'), 'main.1434483388.obb.main.oldversion.obb')
277 self.assertIsNone(apk.get('obbPatchFile'))
278 elif apk['packageName'] == 'obb.main.twoversions':
279 self.assertIsNone(apk.get('obbPatchFile'))
280 if apk['versionCode'] == 1101613:
281 self.assertEqual(apk.get('obbMainFile'), 'main.1101613.obb.main.twoversions.obb')
282 elif apk['versionCode'] == 1101615:
283 self.assertEqual(apk.get('obbMainFile'), 'main.1101615.obb.main.twoversions.obb')
284 elif apk['versionCode'] == 1101617:
285 self.assertEqual(apk.get('obbMainFile'), 'main.1101615.obb.main.twoversions.obb')
287 self.assertTrue(False)
288 elif apk['packageName'] == 'info.guardianproject.urzip':
289 self.assertIsNone(apk.get('obbMainFile'))
290 self.assertIsNone(apk.get('obbPatchFile'))
292 def test_scan_apk(self):
294 fdroidserver.common.fill_config_defaults(config)
295 fdroidserver.common.config = config
296 fdroidserver.update.config = config
297 os.chdir(os.path.join(localmodule, 'tests'))
298 if os.path.basename(os.getcwd()) != 'tests':
299 raise Exception('This test must be run in the "tests/" subdir')
301 apk_info = fdroidserver.update.scan_apk('repo/souch.smsbypass_9.apk')
302 self.assertIsNone(apk_info.get('maxSdkVersion'))
303 self.assertEqual(apk_info.get('versionName'), '0.9')
305 apk_info = fdroidserver.update.scan_apk('repo/duplicate.permisssions_9999999.apk')
306 self.assertIsNone(apk_info.get('versionName'))
307 self.assertEqual(apk_info['icons_src'], {'160': 'res/drawable/ic_launcher.png',
308 '-1': 'res/drawable/ic_launcher.png'})
310 apk_info = fdroidserver.update.scan_apk('org.dyndns.fules.ck_20.apk')
311 self.assertEqual(apk_info['icons_src'], {'240': 'res/drawable-hdpi-v4/icon_launcher.png',
312 '120': 'res/drawable-ldpi-v4/icon_launcher.png',
313 '160': 'res/drawable-mdpi-v4/icon_launcher.png',
314 '-1': 'res/drawable-mdpi-v4/icon_launcher.png'})
315 self.assertEqual(apk_info['icons'], {})
316 self.assertEqual(apk_info['features'], [])
317 self.assertEqual(apk_info['antiFeatures'], set())
318 self.assertEqual(apk_info['versionName'], 'v1.6pre2')
319 self.assertEqual(apk_info['hash'],
320 '897486e1f857c6c0ee32ccbad0e1b8cd82f6d0e65a44a23f13f852d2b63a18c8')
321 self.assertEqual(apk_info['packageName'], 'org.dyndns.fules.ck')
322 self.assertEqual(apk_info['versionCode'], 20)
323 self.assertEqual(apk_info['size'], 132453)
324 self.assertEqual(apk_info['nativecode'],
325 ['arm64-v8a', 'armeabi', 'armeabi-v7a', 'mips', 'mips64', 'x86', 'x86_64'])
326 self.assertEqual(apk_info['minSdkVersion'], '7')
327 self.assertEqual(apk_info['sig'], '9bf7a6a67f95688daec75eab4b1436ac')
328 self.assertEqual(apk_info['hashType'], 'sha256')
329 self.assertEqual(apk_info['targetSdkVersion'], '8')
331 apk_info = fdroidserver.update.scan_apk('org.bitbucket.tickytacky.mirrormirror_4.apk')
332 self.assertEqual(apk_info.get('versionName'), '1.0.3')
333 self.assertEqual(apk_info['icons_src'], {'160': 'res/drawable-mdpi/mirror.png',
334 '-1': 'res/drawable-mdpi/mirror.png'})
336 apk_info = fdroidserver.update.scan_apk('repo/info.zwanenburg.caffeinetile_4.apk')
337 self.assertEqual(apk_info.get('versionName'), '1.3')
338 self.assertEqual(apk_info['icons_src'], {'160': 'res/drawable/ic_coffee_on.xml',
339 '-1': 'res/drawable/ic_coffee_on.xml'})
341 apk_info = fdroidserver.update.scan_apk('repo/com.politedroid_6.apk')
342 self.assertEqual(apk_info.get('versionName'), '1.5')
343 self.assertEqual(apk_info['icons_src'], {'120': 'res/drawable-ldpi-v4/icon.png',
344 '160': 'res/drawable-mdpi-v4/icon.png',
345 '240': 'res/drawable-hdpi-v4/icon.png',
346 '320': 'res/drawable-xhdpi-v4/icon.png',
347 '-1': 'res/drawable-mdpi-v4/icon.png'})
349 apk_info = fdroidserver.update.scan_apk('SpeedoMeterApp.main_1.apk')
350 self.assertEqual(apk_info.get('versionName'), '1.0')
351 self.assertEqual(apk_info['icons_src'], {})
353 def test_scan_apk_no_sig(self):
355 fdroidserver.common.fill_config_defaults(config)
356 fdroidserver.update.config = config
357 os.chdir(os.path.join(localmodule, 'tests'))
358 if os.path.basename(os.getcwd()) != 'tests':
359 raise Exception('This test must be run in the "tests/" subdir')
361 with self.assertRaises(fdroidserver.exception.BuildException):
362 fdroidserver.update.scan_apk('urzip-release-unsigned.apk')
364 def test_process_apk(self):
366 def _build_yaml_representer(dumper, data):
367 '''Creates a YAML representation of a Build instance'''
368 return dumper.represent_dict(data)
371 fdroidserver.common.fill_config_defaults(config)
372 fdroidserver.update.config = config
373 os.chdir(os.path.join(localmodule, 'tests'))
374 if os.path.basename(os.getcwd()) != 'tests':
375 raise Exception('This test must be run in the "tests/" subdir')
377 config['ndk_paths'] = dict()
378 config['accepted_formats'] = ['json', 'txt', 'yml']
379 fdroidserver.common.config = config
380 fdroidserver.update.config = config
382 fdroidserver.update.options = type('', (), {})()
383 fdroidserver.update.options.clean = True
384 fdroidserver.update.options.rename_apks = False
385 fdroidserver.update.options.delete_unknown = True
386 fdroidserver.update.options.allow_disabled_algorithms = False
388 for icon_dir in fdroidserver.update.get_all_icon_dirs('repo'):
389 if not os.path.exists(icon_dir):
390 os.makedirs(icon_dir)
392 knownapks = fdroidserver.common.KnownApks()
393 apkList = ['../urzip.apk', '../org.dyndns.fules.ck_20.apk']
395 for apkName in apkList:
396 _, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo', knownapks,
398 # Don't care about the date added to the repo and relative apkName
401 # avoid AAPT application name bug
404 # ensure that icons have been extracted properly
405 if apkName == '../urzip.apk':
406 self.assertEqual(apk['icon'], 'info.guardianproject.urzip.100.png')
407 if apkName == '../org.dyndns.fules.ck_20.apk':
408 self.assertEqual(apk['icon'], 'org.dyndns.fules.ck.20.png')
409 for density in fdroidserver.update.screen_densities:
410 icon_path = os.path.join(fdroidserver.update.get_icon_dir('repo', density),
412 self.assertTrue(os.path.isfile(icon_path))
413 self.assertTrue(os.path.getsize(icon_path) > 1)
415 savepath = os.path.join('metadata', 'apk', apk['packageName'] + '.yaml')
416 # Uncomment to save APK metadata
417 # with open(savepath, 'w') as f:
418 # yaml.add_representer(fdroidserver.metadata.Build, _build_yaml_representer)
419 # yaml.dump(apk, f, default_flow_style=False)
421 with open(savepath, 'r') as f:
422 frompickle = yaml.load(f)
424 self.assertEqual(apk, frompickle)
426 def test_process_apk_signed_by_disabled_algorithms(self):
428 fdroidserver.common.fill_config_defaults(config)
429 fdroidserver.update.config = config
431 config['ndk_paths'] = dict()
432 config['accepted_formats'] = ['json', 'txt', 'yml']
433 fdroidserver.common.config = config
434 fdroidserver.update.config = config
436 fdroidserver.update.options = type('', (), {})()
437 fdroidserver.update.options.clean = True
438 fdroidserver.update.options.verbose = True
439 fdroidserver.update.options.rename_apks = False
440 fdroidserver.update.options.delete_unknown = True
441 fdroidserver.update.options.allow_disabled_algorithms = False
443 knownapks = fdroidserver.common.KnownApks()
445 tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
447 print('tmptestsdir', tmptestsdir)
448 os.chdir(tmptestsdir)
451 # setup the repo, create icons dirs, etc.
452 fdroidserver.update.process_apks({}, 'repo', knownapks)
453 fdroidserver.update.process_apks({}, 'archive', knownapks)
455 disabledsigs = ['org.bitbucket.tickytacky.mirrormirror_2.apk', ]
456 for apkName in disabledsigs:
457 shutil.copy(os.path.join(self.basedir, apkName),
458 os.path.join(tmptestsdir, 'repo'))
460 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
462 allow_disabled_algorithms=True,
463 archive_bad_sig=False)
464 self.assertFalse(skip)
465 self.assertIsNotNone(apk)
466 self.assertTrue(cachechanged)
467 self.assertFalse(os.path.exists(os.path.join('archive', apkName)))
468 self.assertTrue(os.path.exists(os.path.join('repo', apkName)))
470 javac = config['jarsigner'].replace('jarsigner', 'javac')
471 v = subprocess.check_output([javac, '-version'], stderr=subprocess.STDOUT)[6:-1].decode('utf-8')
472 if LooseVersion(v) < LooseVersion('1.8.0_132'):
473 print('SKIPPING: running tests with old Java (' + v + ')')
476 # this test only works on systems with fully updated Java/jarsigner
477 # that has MD5 listed in jdk.jar.disabledAlgorithms in java.security
478 # https://blogs.oracle.com/java-platform-group/oracle-jre-will-no-longer-trust-md5-signed-code-by-default
479 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
481 allow_disabled_algorithms=False,
482 archive_bad_sig=True)
483 self.assertTrue(skip)
484 self.assertIsNone(apk)
485 self.assertFalse(cachechanged)
486 self.assertTrue(os.path.exists(os.path.join('archive', apkName)))
487 self.assertFalse(os.path.exists(os.path.join('repo', apkName)))
489 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'archive',
491 allow_disabled_algorithms=False,
492 archive_bad_sig=False)
493 self.assertFalse(skip)
494 self.assertIsNotNone(apk)
495 self.assertTrue(cachechanged)
496 self.assertTrue(os.path.exists(os.path.join('archive', apkName)))
497 self.assertFalse(os.path.exists(os.path.join('repo', apkName)))
499 # ensure that icons have been moved to the archive as well
500 for density in fdroidserver.update.screen_densities:
501 icon_path = os.path.join(fdroidserver.update.get_icon_dir('archive', density),
503 self.assertTrue(os.path.isfile(icon_path))
504 self.assertTrue(os.path.getsize(icon_path) > 1)
506 badsigs = ['urzip-badcert.apk', 'urzip-badsig.apk', 'urzip-release-unsigned.apk', ]
507 for apkName in badsigs:
508 shutil.copy(os.path.join(self.basedir, apkName),
509 os.path.join(tmptestsdir, 'repo'))
511 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
513 allow_disabled_algorithms=False,
514 archive_bad_sig=False)
515 self.assertTrue(skip)
516 self.assertIsNone(apk)
517 self.assertFalse(cachechanged)
519 def test_process_invalid_apk(self):
520 os.chdir(os.path.join(localmodule, 'tests'))
521 if os.path.basename(os.getcwd()) != 'tests':
522 raise Exception('This test must be run in the "tests/" subdir')
525 fdroidserver.common.fill_config_defaults(config)
526 fdroidserver.common.config = config
527 fdroidserver.update.config = config
528 fdroidserver.update.options.delete_unknown = False
530 knownapks = fdroidserver.common.KnownApks()
531 apk = 'fake.ota.update_1234.zip' # this is not an APK, scanning should fail
532 (skip, apk, cachechanged) = fdroidserver.update.process_apk({}, apk, 'repo', knownapks,
535 self.assertTrue(skip)
536 self.assertIsNone(apk)
537 self.assertFalse(cachechanged)
539 def test_translate_per_build_anti_features(self):
540 os.chdir(os.path.join(localmodule, 'tests'))
541 if os.path.basename(os.getcwd()) != 'tests':
542 raise Exception('This test must be run in the "tests/" subdir')
545 fdroidserver.common.fill_config_defaults(config)
546 config['ndk_paths'] = dict()
547 config['accepted_formats'] = ['json', 'txt', 'yml']
548 fdroidserver.common.config = config
549 fdroidserver.update.config = config
551 fdroidserver.update.options = type('', (), {})()
552 fdroidserver.update.options.clean = True
553 fdroidserver.update.options.delete_unknown = True
554 fdroidserver.update.options.rename_apks = False
555 fdroidserver.update.options.allow_disabled_algorithms = False
557 apps = fdroidserver.metadata.read_metadata(xref=True)
558 knownapks = fdroidserver.common.KnownApks()
559 apks, cachechanged = fdroidserver.update.process_apks({}, 'repo', knownapks, False)
560 fdroidserver.update.translate_per_build_anti_features(apps, apks)
561 self.assertEqual(len(apks), 14)
564 if apk['packageName'] == 'com.politedroid' and apk['versionCode'] == 3:
565 antiFeatures = apk.get('antiFeatures')
566 self.assertTrue('KnownVuln' in antiFeatures)
567 self.assertEqual(3, len(antiFeatures))
569 self.assertTrue(foundtest)
571 def test_create_metadata_from_template(self):
572 tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
574 print('tmptestsdir', tmptestsdir)
575 os.chdir(tmptestsdir)
578 shutil.copy(os.path.join(localmodule, 'tests', 'urzip.apk'), 'repo')
581 fdroidserver.common.fill_config_defaults(config)
582 config['ndk_paths'] = dict()
583 config['accepted_formats'] = ['json', 'txt', 'yml']
584 fdroidserver.common.config = config
585 fdroidserver.update.config = config
587 fdroidserver.update.options = type('', (), {})()
588 fdroidserver.update.options.clean = True
589 fdroidserver.update.options.delete_unknown = False
590 fdroidserver.update.options.rename_apks = False
591 fdroidserver.update.options.allow_disabled_algorithms = False
593 knownapks = fdroidserver.common.KnownApks()
594 apks, cachechanged = fdroidserver.update.process_apks({}, 'repo', knownapks, False)
595 self.assertEqual(1, len(apks))
598 testfile = 'metadata/info.guardianproject.urzip.yml'
599 # create empty 0 byte .yml file, run read_metadata, it should work
600 open(testfile, 'a').close()
601 apps = fdroidserver.metadata.read_metadata(xref=True)
602 self.assertEqual(1, len(apps))
605 # test using internal template
606 apps = fdroidserver.metadata.read_metadata(xref=True)
607 self.assertEqual(0, len(apps))
608 fdroidserver.update.create_metadata_from_template(apk)
609 self.assertTrue(os.path.exists(testfile))
610 apps = fdroidserver.metadata.read_metadata(xref=True)
611 self.assertEqual(1, len(apps))
612 for app in apps.values():
613 self.assertEqual('urzip', app['Name'])
614 self.assertEqual(1, len(app['Categories']))
617 # test using external template.yml
619 self.assertFalse(os.path.exists(testfile))
620 shutil.copy(os.path.join(localmodule, 'examples', 'template.yml'), tmptestsdir)
621 fdroidserver.update.create_metadata_from_template(apk)
622 self.assertTrue(os.path.exists(testfile))
623 apps = fdroidserver.metadata.read_metadata(xref=True)
624 self.assertEqual(1, len(apps))
625 for app in apps.values():
626 self.assertEqual('urzip', app['Name'])
627 self.assertEqual(1, len(app['Categories']))
628 self.assertEqual('Internet', app['Categories'][0])
630 with open(testfile) as fp:
632 self.assertEqual('urzip', data['Name'])
633 self.assertEqual('urzip', data['Summary'])
635 def test_has_known_vulnerability(self):
637 'org.bitbucket.tickytacky.mirrormirror_1.apk',
638 'org.bitbucket.tickytacky.mirrormirror_2.apk',
639 'org.bitbucket.tickytacky.mirrormirror_3.apk',
640 'org.bitbucket.tickytacky.mirrormirror_4.apk',
641 'org.dyndns.fules.ck_20.apk',
646 'urzip-release-unsigned.apk',
647 'repo/com.politedroid_3.apk',
648 'repo/com.politedroid_4.apk',
649 'repo/com.politedroid_5.apk',
650 'repo/com.politedroid_6.apk',
651 'repo/obb.main.oldversion_1444412523.apk',
652 'repo/obb.mainpatch.current_1619_another-release-key.apk',
653 'repo/obb.mainpatch.current_1619.apk',
654 'repo/obb.main.twoversions_1101613.apk',
655 'repo/obb.main.twoversions_1101615.apk',
656 'repo/obb.main.twoversions_1101617.apk',
657 'repo/urzip-; Рахма́нинов, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢尔盖·.apk',
660 self.assertFalse(fdroidserver.update.has_known_vulnerability(f))
661 with self.assertRaises(fdroidserver.exception.FDroidException):
662 fdroidserver.update.has_known_vulnerability('janus.apk')
664 def test_get_apk_icon_when_src_is_none(self):
666 fdroidserver.common.fill_config_defaults(config)
667 fdroidserver.common.config = config
668 fdroidserver.update.config = config
670 # pylint: disable=protected-access
671 icons_src = fdroidserver.update._get_apk_icons_src('urzip-release.apk', None)
672 assert icons_src == {}
675 if __name__ == "__main__":
676 parser = optparse.OptionParser()
677 parser.add_option("-v", "--verbose", action="store_true", default=False,
678 help="Spew out even more information than normal")
679 (fdroidserver.common.options, args) = parser.parse_args(['--verbose'])
681 newSuite = unittest.TestSuite()
682 newSuite.addTest(unittest.makeSuite(UpdateTest))
683 unittest.main(failfast=False)