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), 13)
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.update.config = config
296 os.chdir(os.path.join(localmodule, 'tests'))
297 if os.path.basename(os.getcwd()) != 'tests':
298 raise Exception('This test must be run in the "tests/" subdir')
300 apk_info = fdroidserver.update.scan_apk('org.dyndns.fules.ck_20.apk')
301 self.assertEqual(apk_info['icons_src'], {'240': 'res/drawable-hdpi-v4/icon_launcher.png',
302 '120': 'res/drawable-ldpi-v4/icon_launcher.png',
303 '160': 'res/drawable-mdpi-v4/icon_launcher.png',
304 '-1': 'res/drawable-mdpi-v4/icon_launcher.png'})
305 self.assertEqual(apk_info['icons'], {})
306 self.assertEqual(apk_info['features'], [])
307 self.assertEqual(apk_info['antiFeatures'], set())
308 self.assertEqual(apk_info['versionName'], 'v1.6pre2')
309 self.assertEqual(apk_info['hash'],
310 '897486e1f857c6c0ee32ccbad0e1b8cd82f6d0e65a44a23f13f852d2b63a18c8')
311 self.assertEqual(apk_info['packageName'], 'org.dyndns.fules.ck')
312 self.assertEqual(apk_info['versionCode'], 20)
313 self.assertEqual(apk_info['size'], 132453)
314 self.assertEqual(apk_info['nativecode'],
315 ['arm64-v8a', 'armeabi', 'armeabi-v7a', 'mips', 'mips64', 'x86', 'x86_64'])
316 self.assertEqual(apk_info['minSdkVersion'], '7')
317 self.assertEqual(apk_info['sig'], '9bf7a6a67f95688daec75eab4b1436ac')
318 self.assertEqual(apk_info['hashType'], 'sha256')
319 self.assertEqual(apk_info['targetSdkVersion'], '8')
321 apk_info = fdroidserver.update.scan_apk('org.bitbucket.tickytacky.mirrormirror_4.apk')
322 self.assertEqual(apk_info['icons_src'], {'160': 'res/drawable-mdpi/mirror.png',
323 '-1': 'res/drawable-mdpi/mirror.png'})
325 apk_info = fdroidserver.update.scan_apk('repo/info.zwanenburg.caffeinetile_4.apk')
326 self.assertEqual(apk_info['icons_src'], {'160': 'res/drawable/ic_coffee_on.xml',
327 '-1': 'res/drawable/ic_coffee_on.xml'})
329 apk_info = fdroidserver.update.scan_apk('repo/com.politedroid_6.apk')
330 self.assertEqual(apk_info['icons_src'], {'120': 'res/drawable-ldpi-v4/icon.png',
331 '160': 'res/drawable-mdpi-v4/icon.png',
332 '240': 'res/drawable-hdpi-v4/icon.png',
333 '320': 'res/drawable-xhdpi-v4/icon.png',
334 '-1': 'res/drawable-mdpi-v4/icon.png'})
336 apk_info = fdroidserver.update.scan_apk('SpeedoMeterApp.main_1.apk')
337 self.assertEqual(apk_info['icons_src'], {})
339 def test_scan_apk_no_sig(self):
341 fdroidserver.common.fill_config_defaults(config)
342 fdroidserver.update.config = config
343 os.chdir(os.path.join(localmodule, 'tests'))
344 if os.path.basename(os.getcwd()) != 'tests':
345 raise Exception('This test must be run in the "tests/" subdir')
347 with self.assertRaises(fdroidserver.exception.BuildException):
348 fdroidserver.update.scan_apk('urzip-release-unsigned.apk')
350 def test_process_apk(self):
352 def _build_yaml_representer(dumper, data):
353 '''Creates a YAML representation of a Build instance'''
354 return dumper.represent_dict(data)
357 fdroidserver.common.fill_config_defaults(config)
358 fdroidserver.update.config = config
359 os.chdir(os.path.join(localmodule, 'tests'))
360 if os.path.basename(os.getcwd()) != 'tests':
361 raise Exception('This test must be run in the "tests/" subdir')
363 config['ndk_paths'] = dict()
364 config['accepted_formats'] = ['json', 'txt', 'yml']
365 fdroidserver.common.config = config
366 fdroidserver.update.config = config
368 fdroidserver.update.options = type('', (), {})()
369 fdroidserver.update.options.clean = True
370 fdroidserver.update.options.rename_apks = False
371 fdroidserver.update.options.delete_unknown = True
372 fdroidserver.update.options.allow_disabled_algorithms = False
374 for icon_dir in fdroidserver.update.get_all_icon_dirs('repo'):
375 if not os.path.exists(icon_dir):
376 os.makedirs(icon_dir)
378 knownapks = fdroidserver.common.KnownApks()
379 apkList = ['../urzip.apk', '../org.dyndns.fules.ck_20.apk']
381 for apkName in apkList:
382 _, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo', knownapks,
384 # Don't care about the date added to the repo and relative apkName
387 # avoid AAPT application name bug
390 # ensure that icons have been extracted properly
391 if apkName == '../urzip.apk':
392 self.assertEqual(apk['icon'], 'info.guardianproject.urzip.100.png')
393 if apkName == '../org.dyndns.fules.ck_20.apk':
394 self.assertEqual(apk['icon'], 'org.dyndns.fules.ck.20.png')
395 for density in fdroidserver.update.screen_densities:
396 icon_path = os.path.join(fdroidserver.update.get_icon_dir('repo', density),
398 self.assertTrue(os.path.isfile(icon_path))
399 self.assertTrue(os.path.getsize(icon_path) > 1)
401 savepath = os.path.join('metadata', 'apk', apk['packageName'] + '.yaml')
402 # Uncomment to save APK metadata
403 # with open(savepath, 'w') as f:
404 # yaml.add_representer(fdroidserver.metadata.Build, _build_yaml_representer)
405 # yaml.dump(apk, f, default_flow_style=False)
407 with open(savepath, 'r') as f:
408 frompickle = yaml.load(f)
410 self.assertEqual(apk, frompickle)
412 def test_process_apk_signed_by_disabled_algorithms(self):
414 fdroidserver.common.fill_config_defaults(config)
415 fdroidserver.update.config = config
417 config['ndk_paths'] = dict()
418 config['accepted_formats'] = ['json', 'txt', 'yml']
419 fdroidserver.common.config = config
420 fdroidserver.update.config = config
422 fdroidserver.update.options = type('', (), {})()
423 fdroidserver.update.options.clean = True
424 fdroidserver.update.options.verbose = True
425 fdroidserver.update.options.rename_apks = False
426 fdroidserver.update.options.delete_unknown = True
427 fdroidserver.update.options.allow_disabled_algorithms = False
429 knownapks = fdroidserver.common.KnownApks()
431 tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
433 print('tmptestsdir', tmptestsdir)
434 os.chdir(tmptestsdir)
437 # setup the repo, create icons dirs, etc.
438 fdroidserver.update.process_apks({}, 'repo', knownapks)
439 fdroidserver.update.process_apks({}, 'archive', knownapks)
441 disabledsigs = ['org.bitbucket.tickytacky.mirrormirror_2.apk', ]
442 for apkName in disabledsigs:
443 shutil.copy(os.path.join(self.basedir, apkName),
444 os.path.join(tmptestsdir, 'repo'))
446 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
448 allow_disabled_algorithms=True,
449 archive_bad_sig=False)
450 self.assertFalse(skip)
451 self.assertIsNotNone(apk)
452 self.assertTrue(cachechanged)
453 self.assertFalse(os.path.exists(os.path.join('archive', apkName)))
454 self.assertTrue(os.path.exists(os.path.join('repo', apkName)))
456 javac = config['jarsigner'].replace('jarsigner', 'javac')
457 v = subprocess.check_output([javac, '-version'], stderr=subprocess.STDOUT)[6:-1].decode('utf-8')
458 if LooseVersion(v) < LooseVersion('1.8.0_132'):
459 print('SKIPPING: running tests with old Java (' + v + ')')
462 # this test only works on systems with fully updated Java/jarsigner
463 # that has MD5 listed in jdk.jar.disabledAlgorithms in java.security
464 # https://blogs.oracle.com/java-platform-group/oracle-jre-will-no-longer-trust-md5-signed-code-by-default
465 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
467 allow_disabled_algorithms=False,
468 archive_bad_sig=True)
469 self.assertTrue(skip)
470 self.assertIsNone(apk)
471 self.assertFalse(cachechanged)
472 self.assertTrue(os.path.exists(os.path.join('archive', apkName)))
473 self.assertFalse(os.path.exists(os.path.join('repo', apkName)))
475 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'archive',
477 allow_disabled_algorithms=False,
478 archive_bad_sig=False)
479 self.assertFalse(skip)
480 self.assertIsNotNone(apk)
481 self.assertTrue(cachechanged)
482 self.assertTrue(os.path.exists(os.path.join('archive', apkName)))
483 self.assertFalse(os.path.exists(os.path.join('repo', apkName)))
485 # ensure that icons have been moved to the archive as well
486 for density in fdroidserver.update.screen_densities:
487 icon_path = os.path.join(fdroidserver.update.get_icon_dir('archive', density),
489 self.assertTrue(os.path.isfile(icon_path))
490 self.assertTrue(os.path.getsize(icon_path) > 1)
492 badsigs = ['urzip-badcert.apk', 'urzip-badsig.apk', 'urzip-release-unsigned.apk', ]
493 for apkName in badsigs:
494 shutil.copy(os.path.join(self.basedir, apkName),
495 os.path.join(tmptestsdir, 'repo'))
497 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
499 allow_disabled_algorithms=False,
500 archive_bad_sig=False)
501 self.assertTrue(skip)
502 self.assertIsNone(apk)
503 self.assertFalse(cachechanged)
505 def test_process_invalid_apk(self):
506 os.chdir(os.path.join(localmodule, 'tests'))
507 if os.path.basename(os.getcwd()) != 'tests':
508 raise Exception('This test must be run in the "tests/" subdir')
511 fdroidserver.common.fill_config_defaults(config)
512 fdroidserver.common.config = config
513 fdroidserver.update.config = config
514 fdroidserver.update.options.delete_unknown = False
516 knownapks = fdroidserver.common.KnownApks()
517 apk = 'fake.ota.update_1234.zip' # this is not an APK, scanning should fail
518 (skip, apk, cachechanged) = fdroidserver.update.process_apk({}, apk, 'repo', knownapks,
521 self.assertTrue(skip)
522 self.assertIsNone(apk)
523 self.assertFalse(cachechanged)
525 def test_translate_per_build_anti_features(self):
526 os.chdir(os.path.join(localmodule, 'tests'))
527 if os.path.basename(os.getcwd()) != 'tests':
528 raise Exception('This test must be run in the "tests/" subdir')
531 fdroidserver.common.fill_config_defaults(config)
532 config['ndk_paths'] = dict()
533 config['accepted_formats'] = ['json', 'txt', 'yml']
534 fdroidserver.common.config = config
535 fdroidserver.update.config = config
537 fdroidserver.update.options = type('', (), {})()
538 fdroidserver.update.options.clean = True
539 fdroidserver.update.options.delete_unknown = True
540 fdroidserver.update.options.rename_apks = False
541 fdroidserver.update.options.allow_disabled_algorithms = False
543 apps = fdroidserver.metadata.read_metadata(xref=True)
544 knownapks = fdroidserver.common.KnownApks()
545 apks, cachechanged = fdroidserver.update.process_apks({}, 'repo', knownapks, False)
546 fdroidserver.update.translate_per_build_anti_features(apps, apks)
547 self.assertEqual(len(apks), 13)
550 if apk['packageName'] == 'com.politedroid' and apk['versionCode'] == 3:
551 antiFeatures = apk.get('antiFeatures')
552 self.assertTrue('KnownVuln' in antiFeatures)
553 self.assertEqual(3, len(antiFeatures))
555 self.assertTrue(foundtest)
557 def test_create_metadata_from_template(self):
558 tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
560 print('tmptestsdir', tmptestsdir)
561 os.chdir(tmptestsdir)
564 shutil.copy(os.path.join(localmodule, 'tests', 'urzip.apk'), 'repo')
567 fdroidserver.common.fill_config_defaults(config)
568 config['ndk_paths'] = dict()
569 config['accepted_formats'] = ['json', 'txt', 'yml']
570 fdroidserver.common.config = config
571 fdroidserver.update.config = config
573 fdroidserver.update.options = type('', (), {})()
574 fdroidserver.update.options.clean = True
575 fdroidserver.update.options.delete_unknown = False
576 fdroidserver.update.options.rename_apks = False
577 fdroidserver.update.options.allow_disabled_algorithms = False
579 knownapks = fdroidserver.common.KnownApks()
580 apks, cachechanged = fdroidserver.update.process_apks({}, 'repo', knownapks, False)
581 self.assertEqual(1, len(apks))
584 testfile = 'metadata/info.guardianproject.urzip.yml'
585 # create empty 0 byte .yml file, run read_metadata, it should work
586 open(testfile, 'a').close()
587 apps = fdroidserver.metadata.read_metadata(xref=True)
588 self.assertEqual(1, len(apps))
591 # test using internal template
592 apps = fdroidserver.metadata.read_metadata(xref=True)
593 self.assertEqual(0, len(apps))
594 fdroidserver.update.create_metadata_from_template(apk)
595 self.assertTrue(os.path.exists(testfile))
596 apps = fdroidserver.metadata.read_metadata(xref=True)
597 self.assertEqual(1, len(apps))
598 for app in apps.values():
599 self.assertEqual('urzip', app['Name'])
600 self.assertEqual(1, len(app['Categories']))
603 # test using external template.yml
605 self.assertFalse(os.path.exists(testfile))
606 shutil.copy(os.path.join(localmodule, 'examples', 'template.yml'), tmptestsdir)
607 fdroidserver.update.create_metadata_from_template(apk)
608 self.assertTrue(os.path.exists(testfile))
609 apps = fdroidserver.metadata.read_metadata(xref=True)
610 self.assertEqual(1, len(apps))
611 for app in apps.values():
612 self.assertEqual('urzip', app['Name'])
613 self.assertEqual(1, len(app['Categories']))
614 self.assertEqual('Internet', app['Categories'][0])
616 with open(testfile) as fp:
618 self.assertEqual('urzip', data['Name'])
619 self.assertEqual('urzip', data['Summary'])
621 def test_has_known_vulnerability(self):
623 'org.bitbucket.tickytacky.mirrormirror_1.apk',
624 'org.bitbucket.tickytacky.mirrormirror_2.apk',
625 'org.bitbucket.tickytacky.mirrormirror_3.apk',
626 'org.bitbucket.tickytacky.mirrormirror_4.apk',
627 'org.dyndns.fules.ck_20.apk',
632 'urzip-release-unsigned.apk',
633 'repo/com.politedroid_3.apk',
634 'repo/com.politedroid_4.apk',
635 'repo/com.politedroid_5.apk',
636 'repo/com.politedroid_6.apk',
637 'repo/obb.main.oldversion_1444412523.apk',
638 'repo/obb.mainpatch.current_1619_another-release-key.apk',
639 'repo/obb.mainpatch.current_1619.apk',
640 'repo/obb.main.twoversions_1101613.apk',
641 'repo/obb.main.twoversions_1101615.apk',
642 'repo/obb.main.twoversions_1101617.apk',
643 'repo/urzip-; Рахма́нинов, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢尔盖·.apk',
646 self.assertFalse(fdroidserver.update.has_known_vulnerability(f))
647 with self.assertRaises(fdroidserver.exception.FDroidException):
648 fdroidserver.update.has_known_vulnerability('janus.apk')
650 def test_get_apk_icon_when_src_is_none(self):
652 fdroidserver.common.fill_config_defaults(config)
653 fdroidserver.common.config = config
654 fdroidserver.update.config = config
656 # pylint: disable=protected-access
657 icons_src = fdroidserver.update._get_apk_icons_src('urzip-release.apk', None)
658 assert icons_src == {}
661 if __name__ == "__main__":
662 parser = optparse.OptionParser()
663 parser.add_option("-v", "--verbose", action="store_true", default=False,
664 help="Spew out even more information than normal")
665 (fdroidserver.common.options, args) = parser.parse_args(['--verbose'])
667 newSuite = unittest.TestSuite()
668 newSuite.addTest(unittest.makeSuite(UpdateTest))
669 unittest.main(failfast=False)