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.assertEqual(apk_info['icons_src'], {'160': 'res/drawable/ic_launcher.png',
307 '-1': 'res/drawable/ic_launcher.png'})
309 apk_info = fdroidserver.update.scan_apk('org.dyndns.fules.ck_20.apk')
310 self.assertEqual(apk_info['icons_src'], {'240': 'res/drawable-hdpi-v4/icon_launcher.png',
311 '120': 'res/drawable-ldpi-v4/icon_launcher.png',
312 '160': 'res/drawable-mdpi-v4/icon_launcher.png',
313 '-1': 'res/drawable-mdpi-v4/icon_launcher.png'})
314 self.assertEqual(apk_info['icons'], {})
315 self.assertEqual(apk_info['features'], [])
316 self.assertEqual(apk_info['antiFeatures'], set())
317 self.assertEqual(apk_info['versionName'], 'v1.6pre2')
318 self.assertEqual(apk_info['hash'],
319 '897486e1f857c6c0ee32ccbad0e1b8cd82f6d0e65a44a23f13f852d2b63a18c8')
320 self.assertEqual(apk_info['packageName'], 'org.dyndns.fules.ck')
321 self.assertEqual(apk_info['versionCode'], 20)
322 self.assertEqual(apk_info['size'], 132453)
323 self.assertEqual(apk_info['nativecode'],
324 ['arm64-v8a', 'armeabi', 'armeabi-v7a', 'mips', 'mips64', 'x86', 'x86_64'])
325 self.assertEqual(apk_info['minSdkVersion'], '7')
326 self.assertEqual(apk_info['sig'], '9bf7a6a67f95688daec75eab4b1436ac')
327 self.assertEqual(apk_info['hashType'], 'sha256')
328 self.assertEqual(apk_info['targetSdkVersion'], '8')
330 apk_info = fdroidserver.update.scan_apk('org.bitbucket.tickytacky.mirrormirror_4.apk')
331 self.assertEqual(apk_info['icons_src'], {'160': 'res/drawable-mdpi/mirror.png',
332 '-1': 'res/drawable-mdpi/mirror.png'})
334 apk_info = fdroidserver.update.scan_apk('repo/info.zwanenburg.caffeinetile_4.apk')
335 self.assertEqual(apk_info['icons_src'], {'160': 'res/drawable/ic_coffee_on.xml',
336 '-1': 'res/drawable/ic_coffee_on.xml'})
338 apk_info = fdroidserver.update.scan_apk('repo/com.politedroid_6.apk')
339 self.assertEqual(apk_info['icons_src'], {'120': 'res/drawable-ldpi-v4/icon.png',
340 '160': 'res/drawable-mdpi-v4/icon.png',
341 '240': 'res/drawable-hdpi-v4/icon.png',
342 '320': 'res/drawable-xhdpi-v4/icon.png',
343 '-1': 'res/drawable-mdpi-v4/icon.png'})
345 apk_info = fdroidserver.update.scan_apk('SpeedoMeterApp.main_1.apk')
346 self.assertEqual(apk_info['icons_src'], {})
348 def test_scan_apk_no_sig(self):
350 fdroidserver.common.fill_config_defaults(config)
351 fdroidserver.update.config = config
352 os.chdir(os.path.join(localmodule, 'tests'))
353 if os.path.basename(os.getcwd()) != 'tests':
354 raise Exception('This test must be run in the "tests/" subdir')
356 with self.assertRaises(fdroidserver.exception.BuildException):
357 fdroidserver.update.scan_apk('urzip-release-unsigned.apk')
359 def test_process_apk(self):
361 def _build_yaml_representer(dumper, data):
362 '''Creates a YAML representation of a Build instance'''
363 return dumper.represent_dict(data)
366 fdroidserver.common.fill_config_defaults(config)
367 fdroidserver.update.config = config
368 os.chdir(os.path.join(localmodule, 'tests'))
369 if os.path.basename(os.getcwd()) != 'tests':
370 raise Exception('This test must be run in the "tests/" subdir')
372 config['ndk_paths'] = dict()
373 config['accepted_formats'] = ['json', 'txt', 'yml']
374 fdroidserver.common.config = config
375 fdroidserver.update.config = config
377 fdroidserver.update.options = type('', (), {})()
378 fdroidserver.update.options.clean = True
379 fdroidserver.update.options.rename_apks = False
380 fdroidserver.update.options.delete_unknown = True
381 fdroidserver.update.options.allow_disabled_algorithms = False
383 for icon_dir in fdroidserver.update.get_all_icon_dirs('repo'):
384 if not os.path.exists(icon_dir):
385 os.makedirs(icon_dir)
387 knownapks = fdroidserver.common.KnownApks()
388 apkList = ['../urzip.apk', '../org.dyndns.fules.ck_20.apk']
390 for apkName in apkList:
391 _, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo', knownapks,
393 # Don't care about the date added to the repo and relative apkName
396 # avoid AAPT application name bug
399 # ensure that icons have been extracted properly
400 if apkName == '../urzip.apk':
401 self.assertEqual(apk['icon'], 'info.guardianproject.urzip.100.png')
402 if apkName == '../org.dyndns.fules.ck_20.apk':
403 self.assertEqual(apk['icon'], 'org.dyndns.fules.ck.20.png')
404 for density in fdroidserver.update.screen_densities:
405 icon_path = os.path.join(fdroidserver.update.get_icon_dir('repo', density),
407 self.assertTrue(os.path.isfile(icon_path))
408 self.assertTrue(os.path.getsize(icon_path) > 1)
410 savepath = os.path.join('metadata', 'apk', apk['packageName'] + '.yaml')
411 # Uncomment to save APK metadata
412 # with open(savepath, 'w') as f:
413 # yaml.add_representer(fdroidserver.metadata.Build, _build_yaml_representer)
414 # yaml.dump(apk, f, default_flow_style=False)
416 with open(savepath, 'r') as f:
417 frompickle = yaml.load(f)
419 self.assertEqual(apk, frompickle)
421 def test_process_apk_signed_by_disabled_algorithms(self):
423 fdroidserver.common.fill_config_defaults(config)
424 fdroidserver.update.config = config
426 config['ndk_paths'] = dict()
427 config['accepted_formats'] = ['json', 'txt', 'yml']
428 fdroidserver.common.config = config
429 fdroidserver.update.config = config
431 fdroidserver.update.options = type('', (), {})()
432 fdroidserver.update.options.clean = True
433 fdroidserver.update.options.verbose = True
434 fdroidserver.update.options.rename_apks = False
435 fdroidserver.update.options.delete_unknown = True
436 fdroidserver.update.options.allow_disabled_algorithms = False
438 knownapks = fdroidserver.common.KnownApks()
440 tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
442 print('tmptestsdir', tmptestsdir)
443 os.chdir(tmptestsdir)
446 # setup the repo, create icons dirs, etc.
447 fdroidserver.update.process_apks({}, 'repo', knownapks)
448 fdroidserver.update.process_apks({}, 'archive', knownapks)
450 disabledsigs = ['org.bitbucket.tickytacky.mirrormirror_2.apk', ]
451 for apkName in disabledsigs:
452 shutil.copy(os.path.join(self.basedir, apkName),
453 os.path.join(tmptestsdir, 'repo'))
455 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
457 allow_disabled_algorithms=True,
458 archive_bad_sig=False)
459 self.assertFalse(skip)
460 self.assertIsNotNone(apk)
461 self.assertTrue(cachechanged)
462 self.assertFalse(os.path.exists(os.path.join('archive', apkName)))
463 self.assertTrue(os.path.exists(os.path.join('repo', apkName)))
465 javac = config['jarsigner'].replace('jarsigner', 'javac')
466 v = subprocess.check_output([javac, '-version'], stderr=subprocess.STDOUT)[6:-1].decode('utf-8')
467 if LooseVersion(v) < LooseVersion('1.8.0_132'):
468 print('SKIPPING: running tests with old Java (' + v + ')')
471 # this test only works on systems with fully updated Java/jarsigner
472 # that has MD5 listed in jdk.jar.disabledAlgorithms in java.security
473 # https://blogs.oracle.com/java-platform-group/oracle-jre-will-no-longer-trust-md5-signed-code-by-default
474 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
476 allow_disabled_algorithms=False,
477 archive_bad_sig=True)
478 self.assertTrue(skip)
479 self.assertIsNone(apk)
480 self.assertFalse(cachechanged)
481 self.assertTrue(os.path.exists(os.path.join('archive', apkName)))
482 self.assertFalse(os.path.exists(os.path.join('repo', apkName)))
484 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'archive',
486 allow_disabled_algorithms=False,
487 archive_bad_sig=False)
488 self.assertFalse(skip)
489 self.assertIsNotNone(apk)
490 self.assertTrue(cachechanged)
491 self.assertTrue(os.path.exists(os.path.join('archive', apkName)))
492 self.assertFalse(os.path.exists(os.path.join('repo', apkName)))
494 # ensure that icons have been moved to the archive as well
495 for density in fdroidserver.update.screen_densities:
496 icon_path = os.path.join(fdroidserver.update.get_icon_dir('archive', density),
498 self.assertTrue(os.path.isfile(icon_path))
499 self.assertTrue(os.path.getsize(icon_path) > 1)
501 badsigs = ['urzip-badcert.apk', 'urzip-badsig.apk', 'urzip-release-unsigned.apk', ]
502 for apkName in badsigs:
503 shutil.copy(os.path.join(self.basedir, apkName),
504 os.path.join(tmptestsdir, 'repo'))
506 skip, apk, cachechanged = fdroidserver.update.process_apk({}, apkName, 'repo',
508 allow_disabled_algorithms=False,
509 archive_bad_sig=False)
510 self.assertTrue(skip)
511 self.assertIsNone(apk)
512 self.assertFalse(cachechanged)
514 def test_process_invalid_apk(self):
515 os.chdir(os.path.join(localmodule, 'tests'))
516 if os.path.basename(os.getcwd()) != 'tests':
517 raise Exception('This test must be run in the "tests/" subdir')
520 fdroidserver.common.fill_config_defaults(config)
521 fdroidserver.common.config = config
522 fdroidserver.update.config = config
523 fdroidserver.update.options.delete_unknown = False
525 knownapks = fdroidserver.common.KnownApks()
526 apk = 'fake.ota.update_1234.zip' # this is not an APK, scanning should fail
527 (skip, apk, cachechanged) = fdroidserver.update.process_apk({}, apk, 'repo', knownapks,
530 self.assertTrue(skip)
531 self.assertIsNone(apk)
532 self.assertFalse(cachechanged)
534 def test_translate_per_build_anti_features(self):
535 os.chdir(os.path.join(localmodule, 'tests'))
536 if os.path.basename(os.getcwd()) != 'tests':
537 raise Exception('This test must be run in the "tests/" subdir')
540 fdroidserver.common.fill_config_defaults(config)
541 config['ndk_paths'] = dict()
542 config['accepted_formats'] = ['json', 'txt', 'yml']
543 fdroidserver.common.config = config
544 fdroidserver.update.config = config
546 fdroidserver.update.options = type('', (), {})()
547 fdroidserver.update.options.clean = True
548 fdroidserver.update.options.delete_unknown = True
549 fdroidserver.update.options.rename_apks = False
550 fdroidserver.update.options.allow_disabled_algorithms = False
552 apps = fdroidserver.metadata.read_metadata(xref=True)
553 knownapks = fdroidserver.common.KnownApks()
554 apks, cachechanged = fdroidserver.update.process_apks({}, 'repo', knownapks, False)
555 fdroidserver.update.translate_per_build_anti_features(apps, apks)
556 self.assertEqual(len(apks), 14)
559 if apk['packageName'] == 'com.politedroid' and apk['versionCode'] == 3:
560 antiFeatures = apk.get('antiFeatures')
561 self.assertTrue('KnownVuln' in antiFeatures)
562 self.assertEqual(3, len(antiFeatures))
564 self.assertTrue(foundtest)
566 def test_create_metadata_from_template(self):
567 tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
569 print('tmptestsdir', tmptestsdir)
570 os.chdir(tmptestsdir)
573 shutil.copy(os.path.join(localmodule, 'tests', 'urzip.apk'), 'repo')
576 fdroidserver.common.fill_config_defaults(config)
577 config['ndk_paths'] = dict()
578 config['accepted_formats'] = ['json', 'txt', 'yml']
579 fdroidserver.common.config = config
580 fdroidserver.update.config = config
582 fdroidserver.update.options = type('', (), {})()
583 fdroidserver.update.options.clean = True
584 fdroidserver.update.options.delete_unknown = False
585 fdroidserver.update.options.rename_apks = False
586 fdroidserver.update.options.allow_disabled_algorithms = False
588 knownapks = fdroidserver.common.KnownApks()
589 apks, cachechanged = fdroidserver.update.process_apks({}, 'repo', knownapks, False)
590 self.assertEqual(1, len(apks))
593 testfile = 'metadata/info.guardianproject.urzip.yml'
594 # create empty 0 byte .yml file, run read_metadata, it should work
595 open(testfile, 'a').close()
596 apps = fdroidserver.metadata.read_metadata(xref=True)
597 self.assertEqual(1, len(apps))
600 # test using internal template
601 apps = fdroidserver.metadata.read_metadata(xref=True)
602 self.assertEqual(0, len(apps))
603 fdroidserver.update.create_metadata_from_template(apk)
604 self.assertTrue(os.path.exists(testfile))
605 apps = fdroidserver.metadata.read_metadata(xref=True)
606 self.assertEqual(1, len(apps))
607 for app in apps.values():
608 self.assertEqual('urzip', app['Name'])
609 self.assertEqual(1, len(app['Categories']))
612 # test using external template.yml
614 self.assertFalse(os.path.exists(testfile))
615 shutil.copy(os.path.join(localmodule, 'examples', 'template.yml'), tmptestsdir)
616 fdroidserver.update.create_metadata_from_template(apk)
617 self.assertTrue(os.path.exists(testfile))
618 apps = fdroidserver.metadata.read_metadata(xref=True)
619 self.assertEqual(1, len(apps))
620 for app in apps.values():
621 self.assertEqual('urzip', app['Name'])
622 self.assertEqual(1, len(app['Categories']))
623 self.assertEqual('Internet', app['Categories'][0])
625 with open(testfile) as fp:
627 self.assertEqual('urzip', data['Name'])
628 self.assertEqual('urzip', data['Summary'])
630 def test_has_known_vulnerability(self):
632 'org.bitbucket.tickytacky.mirrormirror_1.apk',
633 'org.bitbucket.tickytacky.mirrormirror_2.apk',
634 'org.bitbucket.tickytacky.mirrormirror_3.apk',
635 'org.bitbucket.tickytacky.mirrormirror_4.apk',
636 'org.dyndns.fules.ck_20.apk',
641 'urzip-release-unsigned.apk',
642 'repo/com.politedroid_3.apk',
643 'repo/com.politedroid_4.apk',
644 'repo/com.politedroid_5.apk',
645 'repo/com.politedroid_6.apk',
646 'repo/obb.main.oldversion_1444412523.apk',
647 'repo/obb.mainpatch.current_1619_another-release-key.apk',
648 'repo/obb.mainpatch.current_1619.apk',
649 'repo/obb.main.twoversions_1101613.apk',
650 'repo/obb.main.twoversions_1101615.apk',
651 'repo/obb.main.twoversions_1101617.apk',
652 'repo/urzip-; Рахма́нинов, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢尔盖·.apk',
655 self.assertFalse(fdroidserver.update.has_known_vulnerability(f))
656 with self.assertRaises(fdroidserver.exception.FDroidException):
657 fdroidserver.update.has_known_vulnerability('janus.apk')
659 def test_get_apk_icon_when_src_is_none(self):
661 fdroidserver.common.fill_config_defaults(config)
662 fdroidserver.common.config = config
663 fdroidserver.update.config = config
665 # pylint: disable=protected-access
666 icons_src = fdroidserver.update._get_apk_icons_src('urzip-release.apk', None)
667 assert icons_src == {}
670 if __name__ == "__main__":
671 parser = optparse.OptionParser()
672 parser.add_option("-v", "--verbose", action="store_true", default=False,
673 help="Spew out even more information than normal")
674 (fdroidserver.common.options, args) = parser.parse_args(['--verbose'])
676 newSuite = unittest.TestSuite()
677 newSuite.addTest(unittest.makeSuite(UpdateTest))
678 unittest.main(failfast=False)