mirror of
				https://github.com/f-droid/fdroidserver.git
				synced 2025-11-04 06:30:27 +03:00 
			
		
		
		
	Merge branch 'buildbot-subcommands-schedule-verify' into 'master'
new subcommand "schedule_verify" to generate events for apps to verify See merge request fdroid/fdroidserver!1710
This commit is contained in:
		
						commit
						89dcb1aa1f
					
				
					 4 changed files with 310 additions and 29 deletions
				
			
		| 
						 | 
					@ -69,6 +69,7 @@ COMMANDS_INTERNAL = [
 | 
				
			||||||
    "exec",
 | 
					    "exec",
 | 
				
			||||||
    "pull",
 | 
					    "pull",
 | 
				
			||||||
    "push",
 | 
					    "push",
 | 
				
			||||||
 | 
					    "schedule_verify",
 | 
				
			||||||
    "up",
 | 
					    "up",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										163
									
								
								fdroidserver/schedule_verify.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								fdroidserver/schedule_verify.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,163 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# schedule_verify.py - part of the FDroid server tools
 | 
				
			||||||
 | 
					# Copyright (C) 2024-2025, Hans-Christoph Steiner <hans@eds.org>
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU Affero General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""Schedule packages to build and verify.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This creates a list of Application ID/Version Code that need the
 | 
				
			||||||
 | 
					verify process to be run.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Since this is an internal command, the strings are not localized.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import collections
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
 | 
					from argparse import ArgumentParser
 | 
				
			||||||
 | 
					from pathlib import Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from . import common, index, metadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_versions(
 | 
				
			||||||
 | 
					    repo='https://f-droid.org/repo?fingerprint=43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB',
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
 | 
					    """Get the list of versions that need to be built, newest first.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Newest are built first because older versions that are still not
 | 
				
			||||||
 | 
					    built are most likely to be failing builds.  Repeating failed
 | 
				
			||||||
 | 
					    builds mostly results in another failure.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    If there are versions with the same versionCode but different
 | 
				
			||||||
 | 
					    signers, there will still only be a single entry returned.  If the
 | 
				
			||||||
 | 
					    rebuild matches one signature, that is enough.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    data, _ignored = index.download_repo_index_v2(repo)
 | 
				
			||||||
 | 
					    to_schedule = collections.defaultdict(list)
 | 
				
			||||||
 | 
					    for appid, package in data['packages'].items():
 | 
				
			||||||
 | 
					        for version in package['versions'].values():
 | 
				
			||||||
 | 
					            versionCode = version['manifest']['versionCode']
 | 
				
			||||||
 | 
					            ext = common.get_file_extension(version['file']['name'])
 | 
				
			||||||
 | 
					            jsonf = f'unsigned/{appid}_{versionCode}.{ext}.json'
 | 
				
			||||||
 | 
					            if not os.path.exists(jsonf):
 | 
				
			||||||
 | 
					                to_schedule[version['added']].append(
 | 
				
			||||||
 | 
					                    {'applicationId': appid, 'versionCode': versionCode}
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ret = list()
 | 
				
			||||||
 | 
					    for added in sorted(to_schedule, reverse=True):
 | 
				
			||||||
 | 
					        for i in to_schedule[added]:
 | 
				
			||||||
 | 
					            if i not in ret:
 | 
				
			||||||
 | 
					                ret.append(i)
 | 
				
			||||||
 | 
					    return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_scheduled(versions):
 | 
				
			||||||
 | 
					    """Get versions that need to be built and there is local build metadata for it."""
 | 
				
			||||||
 | 
					    apps = metadata.read_metadata()
 | 
				
			||||||
 | 
					    schedule = []
 | 
				
			||||||
 | 
					    for version in versions:
 | 
				
			||||||
 | 
					        app = apps.get(version['applicationId'])
 | 
				
			||||||
 | 
					        if app and not app.get("Disabled"):
 | 
				
			||||||
 | 
					            for build in app.get("Builds", []):
 | 
				
			||||||
 | 
					                versionCode = build['versionCode']
 | 
				
			||||||
 | 
					                if versionCode == version['versionCode'] and not build.get("disable"):
 | 
				
			||||||
 | 
					                    schedule.append(
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            "applicationId": app.id,
 | 
				
			||||||
 | 
					                            "versionCode": versionCode,
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					    return schedule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def sendchange(scheduled, verbose=False):
 | 
				
			||||||
 | 
					    """Use `buildbot sendchange` to submit builds to the queue.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This requires the automatically generated password to authenticate
 | 
				
			||||||
 | 
					    to the buildbot instance, which is created at a static path by the
 | 
				
			||||||
 | 
					    buildbot master:
 | 
				
			||||||
 | 
					    https://gitlab.com/fdroid/buildbot/-/merge_requests/1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    The passwd file's path is hardcoded in the server setup, which is
 | 
				
			||||||
 | 
					    defined outside of fdroidserver.  Think of the path as a variable
 | 
				
			||||||
 | 
					    name for accessing a value from the filesystem.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    git_revision = common.get_head_commit_id('.')
 | 
				
			||||||
 | 
					    passwd = Path('/tmp/fdroid-buildbot-sendchange/passwd').read_text().strip()  # nosec
 | 
				
			||||||
 | 
					    for d in scheduled:
 | 
				
			||||||
 | 
					        command = [
 | 
				
			||||||
 | 
					            'buildbot',
 | 
				
			||||||
 | 
					            'sendchange',
 | 
				
			||||||
 | 
					            '--master=127.0.0.1:9999',
 | 
				
			||||||
 | 
					            f'--auth=fdroid:{passwd}',
 | 
				
			||||||
 | 
					            '--branch=master',
 | 
				
			||||||
 | 
					            '--repository=https://gitlab.com/fdroid/fdroiddata',
 | 
				
			||||||
 | 
					            f'--revision={git_revision}',
 | 
				
			||||||
 | 
					            '--category=verify',
 | 
				
			||||||
 | 
					            f"--who={d['applicationId']}",
 | 
				
			||||||
 | 
					            f"--project={d['applicationId']}",
 | 
				
			||||||
 | 
					            f"--property=versionCode:{d['versionCode']}",
 | 
				
			||||||
 | 
					            f"--property=packageName:{d['applicationId']}",
 | 
				
			||||||
 | 
					            f"metadata/{d['applicationId']}.yml",
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					        if verbose:
 | 
				
			||||||
 | 
					            logging.info(' '.join(command))
 | 
				
			||||||
 | 
					        subprocess.run(command, check=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    parser = ArgumentParser(description="Schedule packages to build and verify.")
 | 
				
			||||||
 | 
					    common.setup_global_opts(parser)
 | 
				
			||||||
 | 
					    parser.add_argument(
 | 
				
			||||||
 | 
					        "url",
 | 
				
			||||||
 | 
					        default='https://f-droid.org/repo?fingerprint=43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB',
 | 
				
			||||||
 | 
					        nargs='?',
 | 
				
			||||||
 | 
					        help='Base URL to mirror, can include the index signing key using the query string: ?fingerprint=',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    parser.add_argument(
 | 
				
			||||||
 | 
					        '--sendchange',
 | 
				
			||||||
 | 
					        action="store_true",
 | 
				
			||||||
 | 
					        help='Call buildbot sendchange with the results instead of printing to stdout.',
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    options = common.parse_args(parser)
 | 
				
			||||||
 | 
					    common.get_config()
 | 
				
			||||||
 | 
					    common.set_console_logging(options.verbose)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # TODO support priority list, and ignore list (see buildbot-sendchange-build)
 | 
				
			||||||
 | 
					    if not os.path.exists('metadata'):
 | 
				
			||||||
 | 
					        logging.error("'metadata/' directory does not exist!")
 | 
				
			||||||
 | 
					        sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    versions = get_versions(options.url)
 | 
				
			||||||
 | 
					    scheduled = get_scheduled(versions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if options.sendchange:
 | 
				
			||||||
 | 
					        sendchange(scheduled, options.verbose)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        print(json.dumps(scheduled))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										111
									
								
								tests/test_schedule_verify.py
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										111
									
								
								tests/test_schedule_verify.py
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,111 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from pathlib import Path
 | 
				
			||||||
 | 
					from unittest import mock, skipUnless
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from fdroidserver import common, schedule_verify
 | 
				
			||||||
 | 
					from .shared_test_code import mkdtemp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					basedir = Path(__file__).parent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FULL_LIST = [
 | 
				
			||||||
 | 
					    {'applicationId': 'org.maxsdkversion', 'versionCode': 4},
 | 
				
			||||||
 | 
					    {'applicationId': 'info.zwanenburg.caffeinetile', 'versionCode': 4},
 | 
				
			||||||
 | 
					    {'applicationId': 'no.min.target.sdk', 'versionCode': 987},
 | 
				
			||||||
 | 
					    {'applicationId': 'souch.smsbypass', 'versionCode': 9},
 | 
				
			||||||
 | 
					    {'applicationId': 'duplicate.permisssions', 'versionCode': 9999999},
 | 
				
			||||||
 | 
					    {'applicationId': 'com.politedroid', 'versionCode': 6},
 | 
				
			||||||
 | 
					    {'applicationId': 'com.politedroid', 'versionCode': 5},
 | 
				
			||||||
 | 
					    {'applicationId': 'com.politedroid', 'versionCode': 4},
 | 
				
			||||||
 | 
					    {'applicationId': 'com.politedroid', 'versionCode': 3},
 | 
				
			||||||
 | 
					    {'applicationId': 'obb.mainpatch.current', 'versionCode': 1619},
 | 
				
			||||||
 | 
					    {'applicationId': 'info.guardianproject.urzip', 'versionCode': 100},
 | 
				
			||||||
 | 
					    {'applicationId': 'obb.main.twoversions', 'versionCode': 1101617},
 | 
				
			||||||
 | 
					    {'applicationId': 'fake.ota.update', 'versionCode': 1234},
 | 
				
			||||||
 | 
					    {'applicationId': 'obb.main.twoversions', 'versionCode': 1101615},
 | 
				
			||||||
 | 
					    {'applicationId': 'obb.main.twoversions', 'versionCode': 1101613},
 | 
				
			||||||
 | 
					    {'applicationId': 'obb.main.oldversion', 'versionCode': 1444412523},
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _mock(repo):  # pylint: disable=unused-argument
 | 
				
			||||||
 | 
					    indexf = basedir / 'repo' / 'index-v2.json'
 | 
				
			||||||
 | 
					    return json.loads(indexf.read_text()), None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Schedule_verifyTest(unittest.TestCase):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self._td = mkdtemp()
 | 
				
			||||||
 | 
					        self.testdir = self._td.name
 | 
				
			||||||
 | 
					        os.chdir(self.testdir)
 | 
				
			||||||
 | 
					        os.mkdir('unsigned')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tearDown(self):
 | 
				
			||||||
 | 
					        self._td.cleanup()
 | 
				
			||||||
 | 
					        common.config = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@skipUnless(False, 'This involves downloading the full index')
 | 
				
			||||||
 | 
					class Schedule_verify_main(Schedule_verifyTest):
 | 
				
			||||||
 | 
					    def test_main_smokecheck(self):
 | 
				
			||||||
 | 
					        schedule_verify.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Schedule_verify_get_versions(Schedule_verifyTest):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        super().setUp()
 | 
				
			||||||
 | 
					        common.config = {'sdk_path': os.getenv('ANDROID_HOME')}
 | 
				
			||||||
 | 
					        common.config['jarsigner'] = common.find_sdk_tools_cmd('jarsigner')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @mock.patch('fdroidserver.index.download_repo_index_v2', _mock)
 | 
				
			||||||
 | 
					    def test_get_versions_none_exist(self):
 | 
				
			||||||
 | 
					        self.assertEqual(FULL_LIST, schedule_verify.get_versions())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @mock.patch('fdroidserver.index.download_repo_index_v2', _mock)
 | 
				
			||||||
 | 
					    def test_get_versions_all_json_exist(self):
 | 
				
			||||||
 | 
					        for d in FULL_LIST:
 | 
				
			||||||
 | 
					            appid = d['applicationId']
 | 
				
			||||||
 | 
					            if appid == 'fake.ota.update':
 | 
				
			||||||
 | 
					                ext = 'zip'
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                ext = 'apk'
 | 
				
			||||||
 | 
					            Path(f"unsigned/{appid}_{d['versionCode']}.{ext}.json").write_text('{}')
 | 
				
			||||||
 | 
					        self.assertEqual([], schedule_verify.get_versions())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @mock.patch('fdroidserver.index.download_repo_index_v2', _mock)
 | 
				
			||||||
 | 
					    def test_get_versions_all_apks_exist(self):
 | 
				
			||||||
 | 
					        for d in FULL_LIST:
 | 
				
			||||||
 | 
					            appid = d['applicationId']
 | 
				
			||||||
 | 
					            if appid != 'fake.ota.update':
 | 
				
			||||||
 | 
					                Path(f"unsigned/{appid}_{d['versionCode']}.apk.json").write_text('{}')
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            [{'applicationId': 'fake.ota.update', 'versionCode': 1234}],
 | 
				
			||||||
 | 
					            schedule_verify.get_versions(),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Schedule_verify_get_scheduled(Schedule_verifyTest):
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        super().setUp()
 | 
				
			||||||
 | 
					        os.chdir(basedir)
 | 
				
			||||||
 | 
					        common.config = {'sdk_path': os.getenv('ANDROID_HOME')}
 | 
				
			||||||
 | 
					        common.config['jarsigner'] = common.find_sdk_tools_cmd('jarsigner')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @mock.patch('fdroidserver.index.download_repo_index_v2', _mock)
 | 
				
			||||||
 | 
					    def test_get_scheduled_none_exist(self):
 | 
				
			||||||
 | 
					        versions = schedule_verify.get_versions(basedir / 'repo')
 | 
				
			||||||
 | 
					        self.assertEqual(
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                {'applicationId': 'souch.smsbypass', 'versionCode': 9},
 | 
				
			||||||
 | 
					                {'applicationId': 'com.politedroid', 'versionCode': 6},
 | 
				
			||||||
 | 
					                {'applicationId': 'com.politedroid', 'versionCode': 5},
 | 
				
			||||||
 | 
					                {'applicationId': 'com.politedroid', 'versionCode': 4},
 | 
				
			||||||
 | 
					                {'applicationId': 'com.politedroid', 'versionCode': 3},
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            schedule_verify.get_scheduled(versions),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
| 
						 | 
					@ -4,56 +4,62 @@ import hashlib
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import unittest
 | 
					import unittest
 | 
				
			||||||
from tempfile import TemporaryDirectory
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from fdroidserver import common, signatures
 | 
					from fdroidserver import common, signatures
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .shared_test_code import TmpCwd
 | 
					from .shared_test_code import mkdtemp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
basedir = os.path.dirname(__file__)
 | 
					basedir = os.path.dirname(__file__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SignaturesTest(unittest.TestCase):
 | 
					class SignaturesTest(unittest.TestCase):
 | 
				
			||||||
    def setUp(self):
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self._td = mkdtemp()
 | 
				
			||||||
 | 
					        self.testdir = self._td.name
 | 
				
			||||||
 | 
					        os.chdir(self.testdir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        common.config = None
 | 
					        common.config = None
 | 
				
			||||||
        config = common.read_config()
 | 
					        config = common.read_config()
 | 
				
			||||||
        config['jarsigner'] = common.find_sdk_tools_cmd('jarsigner')
 | 
					        config['jarsigner'] = common.find_sdk_tools_cmd('jarsigner')
 | 
				
			||||||
        common.config = config
 | 
					        common.config = config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tearDown(self):
 | 
				
			||||||
 | 
					        self._td.cleanup()
 | 
				
			||||||
 | 
					        common.config = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(sys.byteorder == 'big', "androguard is not ported to big-endian")
 | 
					    @unittest.skipIf(sys.byteorder == 'big', "androguard is not ported to big-endian")
 | 
				
			||||||
    def test_main(self):
 | 
					    def test_main(self):
 | 
				
			||||||
        class OptionsFixture:
 | 
					        class OptionsFixture:
 | 
				
			||||||
            APK = [os.path.join(basedir, 'repo', 'com.politedroid_3.apk')]
 | 
					            APK = [os.path.join(basedir, 'repo', 'com.politedroid_3.apk')]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with TemporaryDirectory() as tmpdir, TmpCwd(tmpdir):
 | 
					        signatures.extract(OptionsFixture)
 | 
				
			||||||
            signatures.extract(OptionsFixture)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # check if extracted signatures are where they are supposed to be
 | 
					        # check if extracted signatures are where they are supposed to be
 | 
				
			||||||
            # also verify weather if extracted file contain what they should
 | 
					        # also verify weather if extracted file contain what they should
 | 
				
			||||||
            filesAndHashes = (
 | 
					        filesAndHashes = (
 | 
				
			||||||
                (
 | 
					            (
 | 
				
			||||||
                    os.path.join(
 | 
					                os.path.join(
 | 
				
			||||||
                        'metadata', 'com.politedroid', 'signatures', '3', 'MANIFEST.MF'
 | 
					                    'metadata', 'com.politedroid', 'signatures', '3', 'MANIFEST.MF'
 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    '7dcd83f0c41a75457fd2311bf3c4578f80d684362d74ba8dc52838d353f31cf2',
 | 
					 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                (
 | 
					                '7dcd83f0c41a75457fd2311bf3c4578f80d684362d74ba8dc52838d353f31cf2',
 | 
				
			||||||
                    os.path.join(
 | 
					            ),
 | 
				
			||||||
                        'metadata', 'com.politedroid', 'signatures', '3', 'RELEASE.RSA'
 | 
					            (
 | 
				
			||||||
                    ),
 | 
					                os.path.join(
 | 
				
			||||||
                    '883ef3d5a6e0bf69d2a58d9e255a7930f08a49abc38e216ed054943c99c8fdb4',
 | 
					                    'metadata', 'com.politedroid', 'signatures', '3', 'RELEASE.RSA'
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                (
 | 
					                '883ef3d5a6e0bf69d2a58d9e255a7930f08a49abc38e216ed054943c99c8fdb4',
 | 
				
			||||||
                    os.path.join(
 | 
					            ),
 | 
				
			||||||
                        'metadata', 'com.politedroid', 'signatures', '3', 'RELEASE.SF'
 | 
					            (
 | 
				
			||||||
                    ),
 | 
					                os.path.join(
 | 
				
			||||||
                    '99fbb3211ef5d7c1253f3a7ad4836eadc9905103ce6a75916c40de2831958284',
 | 
					                    'metadata', 'com.politedroid', 'signatures', '3', 'RELEASE.SF'
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
 | 
					                '99fbb3211ef5d7c1253f3a7ad4836eadc9905103ce6a75916c40de2831958284',
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        for path, checksum in filesAndHashes:
 | 
				
			||||||
 | 
					            self.assertTrue(
 | 
				
			||||||
 | 
					                os.path.isfile(path),
 | 
				
			||||||
 | 
					                f'check whether {path!r} was extracted correctly.',
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            for path, checksum in filesAndHashes:
 | 
					            with open(path, 'rb') as f:
 | 
				
			||||||
                self.assertTrue(
 | 
					                self.assertEqual(hashlib.sha256(f.read()).hexdigest(), checksum)
 | 
				
			||||||
                    os.path.isfile(path),
 | 
					 | 
				
			||||||
                    f'check whether {path!r} was extracted correctly.',
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                with open(path, 'rb') as f:
 | 
					 | 
				
			||||||
                    self.assertEqual(hashlib.sha256(f.read()).hexdigest(), checksum)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue