2016-01-04 21:17:58 +01:00
|
|
|
|
#!/usr/bin/env python3
|
2015-07-30 22:13:36 +02:00
|
|
|
|
|
|
|
|
|
# http://www.drdobbs.com/testing/unit-testing-with-python/240165163
|
|
|
|
|
|
|
|
|
|
import inspect
|
2017-11-30 10:14:38 +01:00
|
|
|
|
import logging
|
2015-07-30 22:13:36 +02:00
|
|
|
|
import optparse
|
|
|
|
|
import os
|
2015-08-11 15:33:03 +02:00
|
|
|
|
import shutil
|
2015-07-30 22:13:36 +02:00
|
|
|
|
import sys
|
2015-08-11 15:33:03 +02:00
|
|
|
|
import tempfile
|
2020-05-26 09:48:55 +02:00
|
|
|
|
import textwrap
|
2015-07-30 22:13:36 +02:00
|
|
|
|
import unittest
|
2021-04-14 09:59:13 +02:00
|
|
|
|
import yaml
|
2022-01-14 12:50:44 +01:00
|
|
|
|
from pathlib import Path
|
2020-05-26 09:48:55 +02:00
|
|
|
|
from unittest import mock
|
2015-07-30 22:13:36 +02:00
|
|
|
|
|
|
|
|
|
localmodule = os.path.realpath(
|
2021-05-12 11:28:25 +02:00
|
|
|
|
os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..')
|
|
|
|
|
)
|
2015-07-30 22:13:36 +02:00
|
|
|
|
print('localmodule: ' + localmodule)
|
|
|
|
|
if localmodule not in sys.path:
|
|
|
|
|
sys.path.insert(0, localmodule)
|
|
|
|
|
|
2022-11-22 17:17:45 +01:00
|
|
|
|
from testcommon import TmpCwd
|
|
|
|
|
|
2015-07-30 22:13:36 +02:00
|
|
|
|
import fdroidserver.build
|
|
|
|
|
import fdroidserver.common
|
2018-09-17 22:44:53 +02:00
|
|
|
|
import fdroidserver.metadata
|
2020-06-30 02:47:53 +02:00
|
|
|
|
import fdroidserver.scanner
|
2022-06-06 13:43:19 +02:00
|
|
|
|
import fdroidserver.vmtools
|
2022-11-22 17:17:45 +01:00
|
|
|
|
from testcommon import mkdtemp
|
2015-07-30 22:13:36 +02:00
|
|
|
|
|
|
|
|
|
|
2021-05-12 11:28:25 +02:00
|
|
|
|
class FakeProcess:
|
|
|
|
|
output = 'fake output'
|
|
|
|
|
returncode = 0
|
|
|
|
|
|
|
|
|
|
def __init__(self, args, **kwargs):
|
|
|
|
|
print('FakeFDroidPopen', args, kwargs)
|
|
|
|
|
|
|
|
|
|
|
2023-05-05 09:27:46 +02:00
|
|
|
|
class Options:
|
|
|
|
|
keep_when_not_allowed = False
|
|
|
|
|
|
|
|
|
|
|
2015-07-30 22:13:36 +02:00
|
|
|
|
class BuildTest(unittest.TestCase):
|
|
|
|
|
'''fdroidserver/build.py'''
|
|
|
|
|
|
2017-11-30 10:14:38 +01:00
|
|
|
|
def setUp(self):
|
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
2020-11-27 13:36:27 +01:00
|
|
|
|
logger = logging.getLogger('androguard.axml')
|
|
|
|
|
logger.setLevel(logging.INFO) # tame the axml debug messages
|
2017-11-30 10:14:38 +01:00
|
|
|
|
self.basedir = os.path.join(localmodule, 'tests')
|
|
|
|
|
os.chdir(self.basedir)
|
2021-03-22 14:51:59 +01:00
|
|
|
|
fdroidserver.common.config = None
|
|
|
|
|
fdroidserver.build.config = None
|
2023-05-05 09:27:46 +02:00
|
|
|
|
fdroidserver.build.options = None
|
2022-11-22 17:17:45 +01:00
|
|
|
|
self._td = mkdtemp()
|
|
|
|
|
self.testdir = self._td.name
|
|
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
|
os.chdir(self.basedir)
|
|
|
|
|
self._td.cleanup()
|
2017-11-30 10:14:38 +01:00
|
|
|
|
|
2021-04-14 09:59:13 +02:00
|
|
|
|
def create_fake_android_home(self, d):
|
|
|
|
|
os.makedirs(os.path.join(d, 'build-tools'), exist_ok=True)
|
|
|
|
|
os.makedirs(os.path.join(d, 'platform-tools'), exist_ok=True)
|
|
|
|
|
os.makedirs(os.path.join(d, 'tools'), exist_ok=True)
|
|
|
|
|
|
2018-09-17 22:44:53 +02:00
|
|
|
|
def test_get_apk_metadata(self):
|
|
|
|
|
config = dict()
|
|
|
|
|
fdroidserver.common.fill_config_defaults(config)
|
|
|
|
|
fdroidserver.common.config = config
|
|
|
|
|
fdroidserver.build.config = config
|
|
|
|
|
try:
|
|
|
|
|
config['aapt'] = fdroidserver.common.find_sdk_tools_cmd('aapt')
|
|
|
|
|
except fdroidserver.exception.FDroidException:
|
|
|
|
|
pass # aapt is not required if androguard is present
|
|
|
|
|
|
|
|
|
|
testcases = [
|
2021-06-08 15:31:55 +02:00
|
|
|
|
(
|
|
|
|
|
'repo/obb.main.twoversions_1101613.apk',
|
|
|
|
|
'obb.main.twoversions',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
1101613,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'0.1',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'org.bitbucket.tickytacky.mirrormirror_1.apk',
|
|
|
|
|
'org.bitbucket.tickytacky.mirrormirror',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
1,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'1.0',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'org.bitbucket.tickytacky.mirrormirror_2.apk',
|
|
|
|
|
'org.bitbucket.tickytacky.mirrormirror',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
2,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'1.0.1',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'org.bitbucket.tickytacky.mirrormirror_3.apk',
|
|
|
|
|
'org.bitbucket.tickytacky.mirrormirror',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
3,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'1.0.2',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'org.bitbucket.tickytacky.mirrormirror_4.apk',
|
|
|
|
|
'org.bitbucket.tickytacky.mirrormirror',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
4,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'1.0.3',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'org.dyndns.fules.ck_20.apk',
|
|
|
|
|
'org.dyndns.fules.ck',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
20,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'v1.6pre2',
|
|
|
|
|
[
|
|
|
|
|
'arm64-v8a',
|
|
|
|
|
'armeabi',
|
|
|
|
|
'armeabi-v7a',
|
|
|
|
|
'mips',
|
|
|
|
|
'mips64',
|
|
|
|
|
'x86',
|
|
|
|
|
'x86_64',
|
|
|
|
|
],
|
|
|
|
|
),
|
2022-09-14 03:45:24 +02:00
|
|
|
|
('urzip.apk', 'info.guardianproject.urzip', 100, '0.1', None),
|
|
|
|
|
('urzip-badcert.apk', 'info.guardianproject.urzip', 100, '0.1', None),
|
|
|
|
|
('urzip-badsig.apk', 'info.guardianproject.urzip', 100, '0.1', None),
|
|
|
|
|
('urzip-release.apk', 'info.guardianproject.urzip', 100, '0.1', None),
|
2021-06-08 15:31:55 +02:00
|
|
|
|
(
|
|
|
|
|
'urzip-release-unsigned.apk',
|
|
|
|
|
'info.guardianproject.urzip',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
100,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'0.1',
|
|
|
|
|
None,
|
|
|
|
|
),
|
2022-09-14 03:45:24 +02:00
|
|
|
|
('repo/com.politedroid_3.apk', 'com.politedroid', 3, '1.2', None),
|
|
|
|
|
('repo/com.politedroid_4.apk', 'com.politedroid', 4, '1.3', None),
|
|
|
|
|
('repo/com.politedroid_5.apk', 'com.politedroid', 5, '1.4', None),
|
|
|
|
|
('repo/com.politedroid_6.apk', 'com.politedroid', 6, '1.5', None),
|
2021-06-08 15:31:55 +02:00
|
|
|
|
(
|
|
|
|
|
'repo/duplicate.permisssions_9999999.apk',
|
|
|
|
|
'duplicate.permisssions',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
9999999,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'repo/info.zwanenburg.caffeinetile_4.apk',
|
|
|
|
|
'info.zwanenburg.caffeinetile',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
4,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'1.3',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'repo/obb.main.oldversion_1444412523.apk',
|
|
|
|
|
'obb.main.oldversion',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
1444412523,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'0.1',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'repo/obb.mainpatch.current_1619_another-release-key.apk',
|
|
|
|
|
'obb.mainpatch.current',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
1619,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'0.1',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'repo/obb.mainpatch.current_1619.apk',
|
|
|
|
|
'obb.mainpatch.current',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
1619,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'0.1',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'repo/obb.main.twoversions_1101613.apk',
|
|
|
|
|
'obb.main.twoversions',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
1101613,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'0.1',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'repo/obb.main.twoversions_1101615.apk',
|
|
|
|
|
'obb.main.twoversions',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
1101615,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'0.1',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'repo/obb.main.twoversions_1101617.apk',
|
|
|
|
|
'obb.main.twoversions',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
1101617,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'0.1',
|
|
|
|
|
None,
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
'repo/urzip-; Рахма́, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢·.apk',
|
|
|
|
|
'info.guardianproject.urzip',
|
2022-09-14 03:45:24 +02:00
|
|
|
|
100,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
'0.1',
|
|
|
|
|
None,
|
|
|
|
|
),
|
2018-09-17 22:44:53 +02:00
|
|
|
|
]
|
|
|
|
|
for apkfilename, appid, versionCode, versionName, nativecode in testcases:
|
|
|
|
|
app = fdroidserver.metadata.App()
|
|
|
|
|
app.id = appid
|
|
|
|
|
build = fdroidserver.metadata.Build()
|
|
|
|
|
build.buildjni = ['yes'] if nativecode else build.buildjni
|
|
|
|
|
build.versionCode = versionCode
|
|
|
|
|
build.versionName = versionName
|
|
|
|
|
vc, vn = fdroidserver.build.get_metadata_from_apk(app, build, apkfilename)
|
|
|
|
|
self.assertEqual(versionCode, vc)
|
|
|
|
|
self.assertEqual(versionName, vn)
|
|
|
|
|
|
2023-04-12 09:14:05 +02:00
|
|
|
|
@mock.patch('fdroidserver.common.get_apk_id')
|
|
|
|
|
@mock.patch('fdroidserver.build.FDroidPopen')
|
|
|
|
|
@mock.patch('fdroidserver.common.is_apk_and_debuggable', lambda f: False)
|
|
|
|
|
@mock.patch('fdroidserver.common.get_native_code', lambda f: 'x86')
|
|
|
|
|
def test_build_local_maven(self, fake_FDroidPopen, fake_get_apk_id):
|
|
|
|
|
"""Test build_local() with a maven project"""
|
|
|
|
|
|
|
|
|
|
# pylint: disable=unused-argument
|
|
|
|
|
def _side_effect(cmd, cwd=None):
|
|
|
|
|
p = mock.MagicMock()
|
|
|
|
|
p.output = '[INFO] fake apkbuilder target/no.apk'
|
|
|
|
|
with open(os.path.join(self.testdir, 'target', 'no.apk'), 'w') as fp:
|
|
|
|
|
fp.write('placeholder')
|
|
|
|
|
p.returncode = 0
|
|
|
|
|
return p
|
|
|
|
|
|
|
|
|
|
fake_FDroidPopen.side_effect = _side_effect
|
|
|
|
|
os.chdir(self.testdir)
|
|
|
|
|
os.mkdir('target')
|
|
|
|
|
config = dict()
|
|
|
|
|
fdroidserver.common.fill_config_defaults(config)
|
|
|
|
|
fdroidserver.common.config = config
|
|
|
|
|
fdroidserver.build.config = config
|
|
|
|
|
fdroidserver.build.options = mock.Mock()
|
|
|
|
|
fdroidserver.build.options.scan_binary = False
|
|
|
|
|
fdroidserver.build.options.notarball = True
|
|
|
|
|
fdroidserver.build.options.skipscan = False
|
|
|
|
|
|
|
|
|
|
app = fdroidserver.metadata.App()
|
|
|
|
|
app.id = 'mocked.app.id'
|
|
|
|
|
build = fdroidserver.metadata.Build()
|
|
|
|
|
build.commit = '1.0'
|
|
|
|
|
build.versionCode = 1
|
|
|
|
|
build.versionName = '1.0'
|
|
|
|
|
fake_get_apk_id.side_effect = lambda f: (
|
|
|
|
|
app.id,
|
|
|
|
|
build.versionCode,
|
|
|
|
|
build.versionName,
|
|
|
|
|
)
|
|
|
|
|
vcs = mock.Mock()
|
|
|
|
|
|
|
|
|
|
build.maven = 'yes@..'
|
|
|
|
|
fdroidserver.build.build_local(
|
|
|
|
|
app,
|
|
|
|
|
build,
|
|
|
|
|
vcs,
|
|
|
|
|
build_dir=self.testdir,
|
|
|
|
|
output_dir=self.testdir,
|
|
|
|
|
log_dir=os.getcwd(),
|
|
|
|
|
srclib_dir=None,
|
|
|
|
|
extlib_dir=None,
|
|
|
|
|
tmp_dir=None,
|
|
|
|
|
force=False,
|
|
|
|
|
onserver=True,
|
|
|
|
|
refresh=False,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
build.maven = 'yes'
|
|
|
|
|
fdroidserver.build.build_local(
|
|
|
|
|
app,
|
|
|
|
|
build,
|
|
|
|
|
vcs,
|
|
|
|
|
build_dir=self.testdir,
|
|
|
|
|
output_dir=self.testdir,
|
|
|
|
|
log_dir=os.getcwd(),
|
|
|
|
|
srclib_dir=None,
|
|
|
|
|
extlib_dir=None,
|
|
|
|
|
tmp_dir=None,
|
|
|
|
|
force=False,
|
|
|
|
|
onserver=True,
|
|
|
|
|
refresh=False,
|
|
|
|
|
)
|
|
|
|
|
|
2022-01-14 12:50:44 +01:00
|
|
|
|
@mock.patch('sdkmanager.build_package_list', lambda use_net: None)
|
2021-05-12 11:28:25 +02:00
|
|
|
|
def test_build_local_ndk(self):
|
|
|
|
|
"""Test if `fdroid build` detects installed NDKs and auto-installs when missing"""
|
2022-11-22 17:17:45 +01:00
|
|
|
|
with tempfile.TemporaryDirectory() as testdir, TmpCwd(
|
|
|
|
|
testdir
|
|
|
|
|
), tempfile.TemporaryDirectory() as sdk_path:
|
|
|
|
|
config = {'ndk_paths': {}, 'sdk_path': sdk_path}
|
|
|
|
|
fdroidserver.common.config = config
|
|
|
|
|
fdroidserver.build.config = config
|
|
|
|
|
fdroidserver.build.options = mock.Mock()
|
|
|
|
|
fdroidserver.build.options.scan_binary = False
|
|
|
|
|
fdroidserver.build.options.notarball = True
|
|
|
|
|
fdroidserver.build.options.skipscan = True
|
2021-05-12 11:28:25 +02:00
|
|
|
|
|
2022-11-22 17:17:45 +01:00
|
|
|
|
app = fdroidserver.metadata.App()
|
|
|
|
|
app.id = 'mocked.app.id'
|
|
|
|
|
build = fdroidserver.metadata.Build()
|
|
|
|
|
build.commit = '1.0'
|
|
|
|
|
build.output = app.id + '.apk'
|
|
|
|
|
build.versionCode = 1
|
|
|
|
|
build.versionName = '1.0'
|
|
|
|
|
build.ndk = 'r21e' # aka 21.4.7075529
|
2022-01-14 12:50:44 +01:00
|
|
|
|
ndk_version = '21.4.7075529'
|
|
|
|
|
ndk_dir = Path(config['sdk_path']) / 'ndk' / ndk_version
|
2022-11-22 17:17:45 +01:00
|
|
|
|
vcs = mock.Mock()
|
|
|
|
|
|
|
|
|
|
def make_fake_apk(output, build):
|
|
|
|
|
with open(build.output, 'w') as fp:
|
|
|
|
|
fp.write('APK PLACEHOLDER')
|
|
|
|
|
return output
|
|
|
|
|
|
2022-01-14 12:50:44 +01:00
|
|
|
|
# pylint: disable=unused-argument
|
|
|
|
|
def fake_sdkmanager_install(to_install, android_home=None):
|
|
|
|
|
ndk_dir.mkdir(parents=True)
|
|
|
|
|
self.assertNotEqual(ndk_version, to_install) # converts r21e to version
|
|
|
|
|
with (ndk_dir / 'source.properties').open('w') as fp:
|
|
|
|
|
fp.write('Pkg.Revision = %s\n' % ndk_version)
|
2022-11-22 17:17:45 +01:00
|
|
|
|
|
|
|
|
|
# use "as _ignored" just to make a pretty layout
|
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.replace_build_vars', wraps=make_fake_apk
|
|
|
|
|
) as _ignored, mock.patch(
|
|
|
|
|
'fdroidserver.common.get_native_code', return_value='x86'
|
|
|
|
|
) as _ignored, mock.patch(
|
|
|
|
|
'fdroidserver.common.get_apk_id',
|
|
|
|
|
return_value=(app.id, build.versionCode, build.versionName),
|
|
|
|
|
) as _ignored, mock.patch(
|
|
|
|
|
'fdroidserver.common.sha256sum',
|
|
|
|
|
return_value='ad7ce5467e18d40050dc51b8e7affc3e635c85bd8c59be62de32352328ed467e',
|
|
|
|
|
) as _ignored, mock.patch(
|
|
|
|
|
'fdroidserver.common.is_apk_and_debuggable', return_value=False
|
|
|
|
|
) as _ignored, mock.patch(
|
|
|
|
|
'fdroidserver.build.FDroidPopen', FakeProcess
|
|
|
|
|
) as _ignored, mock.patch(
|
2022-01-14 12:50:44 +01:00
|
|
|
|
'sdkmanager.install', wraps=fake_sdkmanager_install
|
2022-11-22 17:17:45 +01:00
|
|
|
|
) as _ignored:
|
|
|
|
|
_ignored # silence the linters
|
|
|
|
|
with self.assertRaises(
|
|
|
|
|
fdroidserver.exception.FDroidException,
|
|
|
|
|
msg="No NDK setup, `fdroid build` should fail with error",
|
|
|
|
|
):
|
|
|
|
|
fdroidserver.build.build_local(
|
|
|
|
|
app,
|
|
|
|
|
build,
|
|
|
|
|
vcs,
|
|
|
|
|
build_dir=testdir,
|
|
|
|
|
output_dir=testdir,
|
|
|
|
|
log_dir=None,
|
|
|
|
|
srclib_dir=None,
|
|
|
|
|
extlib_dir=None,
|
|
|
|
|
tmp_dir=None,
|
|
|
|
|
force=False,
|
|
|
|
|
onserver=False,
|
|
|
|
|
refresh=False,
|
|
|
|
|
)
|
|
|
|
|
# now run `fdroid build --onserver`
|
2022-01-14 12:50:44 +01:00
|
|
|
|
print('now run `fdroid build --onserver`')
|
|
|
|
|
self.assertFalse(ndk_dir.exists())
|
|
|
|
|
self.assertFalse('r21e' in config['ndk_paths'])
|
|
|
|
|
self.assertFalse(ndk_version in config['ndk_paths'])
|
|
|
|
|
fdroidserver.build.build_local(
|
|
|
|
|
app,
|
|
|
|
|
build,
|
|
|
|
|
vcs,
|
|
|
|
|
build_dir=testdir,
|
|
|
|
|
output_dir=testdir,
|
|
|
|
|
log_dir=os.getcwd(),
|
|
|
|
|
srclib_dir=None,
|
|
|
|
|
extlib_dir=None,
|
|
|
|
|
tmp_dir=None,
|
|
|
|
|
force=False,
|
|
|
|
|
onserver=True,
|
|
|
|
|
refresh=False,
|
|
|
|
|
)
|
|
|
|
|
self.assertTrue(ndk_dir.exists())
|
|
|
|
|
self.assertTrue(os.path.exists(config['ndk_paths'][ndk_version]))
|
|
|
|
|
# All paths in the config must be strings, never pathlib.Path instances
|
|
|
|
|
self.assertIsInstance(config['ndk_paths'][ndk_version], str)
|
|
|
|
|
|
|
|
|
|
@mock.patch('sdkmanager.build_package_list', lambda use_net: None)
|
|
|
|
|
@mock.patch('fdroidserver.build.FDroidPopen', FakeProcess)
|
|
|
|
|
@mock.patch('fdroidserver.common.get_native_code', lambda _ignored: 'x86')
|
|
|
|
|
@mock.patch('fdroidserver.common.is_apk_and_debuggable', lambda _ignored: False)
|
|
|
|
|
@mock.patch(
|
|
|
|
|
'fdroidserver.common.sha256sum',
|
|
|
|
|
lambda f: 'ad7ce5467e18d40050dc51b8e7affc3e635c85bd8c59be62de32352328ed467e',
|
|
|
|
|
)
|
|
|
|
|
def test_build_local_ndk_some_installed(self):
|
|
|
|
|
"""Test if `fdroid build` detects installed NDKs and auto-installs when missing"""
|
|
|
|
|
with tempfile.TemporaryDirectory() as testdir, TmpCwd(
|
|
|
|
|
testdir
|
|
|
|
|
), tempfile.TemporaryDirectory() as sdk_path:
|
|
|
|
|
ndk_r24 = os.path.join(sdk_path, 'ndk', '24.0.8215888')
|
|
|
|
|
os.makedirs(ndk_r24)
|
|
|
|
|
with open(os.path.join(ndk_r24, 'source.properties'), 'w') as fp:
|
|
|
|
|
fp.write('Pkg.Revision = 24.0.8215888\n')
|
|
|
|
|
config = {'ndk_paths': {'r24': ndk_r24}, 'sdk_path': sdk_path}
|
|
|
|
|
fdroidserver.common.config = config
|
|
|
|
|
fdroidserver.build.config = config
|
|
|
|
|
fdroidserver.build.options = mock.Mock()
|
|
|
|
|
fdroidserver.build.options.scan_binary = False
|
|
|
|
|
fdroidserver.build.options.notarball = True
|
|
|
|
|
fdroidserver.build.options.skipscan = True
|
|
|
|
|
|
|
|
|
|
app = fdroidserver.metadata.App()
|
|
|
|
|
app.id = 'mocked.app.id'
|
|
|
|
|
build = fdroidserver.metadata.Build()
|
|
|
|
|
build.commit = '1.0'
|
|
|
|
|
build.output = app.id + '.apk'
|
|
|
|
|
build.versionCode = 1
|
|
|
|
|
build.versionName = '1.0'
|
|
|
|
|
build.ndk = 'r21e' # aka 21.4.7075529
|
|
|
|
|
ndk_version = '21.4.7075529'
|
|
|
|
|
ndk_dir = Path(config['sdk_path']) / 'ndk' / ndk_version
|
|
|
|
|
vcs = mock.Mock()
|
|
|
|
|
|
|
|
|
|
def make_fake_apk(output, build):
|
|
|
|
|
with open(build.output, 'w') as fp:
|
|
|
|
|
fp.write('APK PLACEHOLDER')
|
|
|
|
|
return output
|
|
|
|
|
|
|
|
|
|
# pylint: disable=unused-argument
|
|
|
|
|
def fake_sdkmanager_install(to_install, android_home=None):
|
|
|
|
|
ndk_dir.mkdir(parents=True)
|
|
|
|
|
self.assertNotEqual(ndk_version, to_install) # converts r21e to version
|
|
|
|
|
with (ndk_dir / 'source.properties').open('w') as fp:
|
|
|
|
|
fp.write('Pkg.Revision = %s\n' % ndk_version)
|
|
|
|
|
|
|
|
|
|
# use "as _ignored" just to make a pretty layout
|
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.replace_build_vars', wraps=make_fake_apk
|
|
|
|
|
) as _ignored, mock.patch(
|
|
|
|
|
'fdroidserver.common.get_apk_id',
|
|
|
|
|
return_value=(app.id, build.versionCode, build.versionName),
|
|
|
|
|
) as _ignored, mock.patch(
|
|
|
|
|
'sdkmanager.install', wraps=fake_sdkmanager_install
|
|
|
|
|
) as _ignored:
|
|
|
|
|
_ignored # silence the linters
|
|
|
|
|
self.assertFalse(ndk_dir.exists())
|
|
|
|
|
self.assertFalse('r21e' in config['ndk_paths'])
|
|
|
|
|
self.assertFalse(ndk_version in config['ndk_paths'])
|
2021-05-12 11:28:25 +02:00
|
|
|
|
fdroidserver.build.build_local(
|
|
|
|
|
app,
|
|
|
|
|
build,
|
|
|
|
|
vcs,
|
|
|
|
|
build_dir=testdir,
|
|
|
|
|
output_dir=testdir,
|
2022-11-22 17:17:45 +01:00
|
|
|
|
log_dir=os.getcwd(),
|
2021-05-12 11:28:25 +02:00
|
|
|
|
srclib_dir=None,
|
|
|
|
|
extlib_dir=None,
|
|
|
|
|
tmp_dir=None,
|
|
|
|
|
force=False,
|
2022-11-22 17:17:45 +01:00
|
|
|
|
onserver=True,
|
2021-05-12 11:28:25 +02:00
|
|
|
|
refresh=False,
|
|
|
|
|
)
|
2022-01-14 12:50:44 +01:00
|
|
|
|
self.assertTrue(ndk_dir.exists())
|
|
|
|
|
self.assertTrue(os.path.exists(config['ndk_paths'][ndk_version]))
|
2021-05-12 11:28:25 +02:00
|
|
|
|
|
2020-05-26 09:48:55 +02:00
|
|
|
|
def test_build_local_clean(self):
|
|
|
|
|
"""Test if `fdroid build` cleans ant and gradle build products"""
|
2022-11-22 17:17:45 +01:00
|
|
|
|
os.chdir(self.testdir)
|
2020-05-26 09:48:55 +02:00
|
|
|
|
config = dict()
|
|
|
|
|
fdroidserver.common.fill_config_defaults(config)
|
|
|
|
|
fdroidserver.common.config = config
|
2020-06-15 20:03:19 +02:00
|
|
|
|
fdroidserver.build.config = config
|
2020-05-26 09:48:55 +02:00
|
|
|
|
fdroidserver.build.options = mock.Mock()
|
2020-06-15 20:03:19 +02:00
|
|
|
|
fdroidserver.build.options.scan_binary = False
|
2020-05-26 09:48:55 +02:00
|
|
|
|
fdroidserver.build.options.notarball = True
|
|
|
|
|
fdroidserver.build.options.skipscan = False
|
|
|
|
|
|
|
|
|
|
app = fdroidserver.metadata.App()
|
|
|
|
|
app.id = 'mocked.app.id'
|
|
|
|
|
build = fdroidserver.metadata.Build()
|
|
|
|
|
build.commit = '1.0'
|
|
|
|
|
build.output = app.id + '.apk'
|
2020-06-03 15:12:04 +02:00
|
|
|
|
build.scandelete = ['baz.so']
|
|
|
|
|
build.scanignore = ['foo.aar']
|
2022-09-14 03:45:24 +02:00
|
|
|
|
build.versionCode = 1
|
2020-05-26 09:48:55 +02:00
|
|
|
|
build.versionName = '1.0'
|
|
|
|
|
vcs = mock.Mock()
|
|
|
|
|
|
|
|
|
|
os.mkdir('reports')
|
|
|
|
|
os.mkdir('target')
|
|
|
|
|
|
|
|
|
|
for f in ('baz.so', 'foo.aar', 'gradle-wrapper.jar'):
|
|
|
|
|
with open(f, 'w') as fp:
|
|
|
|
|
fp.write('placeholder')
|
|
|
|
|
self.assertTrue(os.path.exists(f))
|
|
|
|
|
|
|
|
|
|
os.mkdir('build')
|
|
|
|
|
os.mkdir('build/reports')
|
2021-06-14 15:38:37 +02:00
|
|
|
|
with open('build.gradle', 'w', encoding='utf-8') as fp:
|
2020-05-26 09:48:55 +02:00
|
|
|
|
fp.write('// placeholder')
|
|
|
|
|
|
|
|
|
|
os.mkdir('bin')
|
|
|
|
|
os.mkdir('gen')
|
2021-06-14 15:38:37 +02:00
|
|
|
|
with open('build.xml', 'w', encoding='utf-8') as fp:
|
2021-06-07 11:49:21 +02:00
|
|
|
|
fp.write(
|
|
|
|
|
textwrap.dedent(
|
|
|
|
|
"""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2020-05-26 09:48:55 +02:00
|
|
|
|
<project basedir="." default="clean" name="mockapp">
|
|
|
|
|
<target name="release"/>
|
|
|
|
|
<target name="clean"/>
|
2021-06-07 11:49:21 +02:00
|
|
|
|
</project>"""
|
|
|
|
|
)
|
|
|
|
|
)
|
2020-05-26 09:48:55 +02:00
|
|
|
|
|
|
|
|
|
def make_fake_apk(output, build):
|
|
|
|
|
with open(build.output, 'w') as fp:
|
|
|
|
|
fp.write('APK PLACEHOLDER')
|
|
|
|
|
return output
|
|
|
|
|
|
|
|
|
|
with mock.patch('fdroidserver.common.replace_build_vars', wraps=make_fake_apk):
|
|
|
|
|
with mock.patch('fdroidserver.common.get_native_code', return_value='x86'):
|
2021-06-08 15:31:55 +02:00
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.get_apk_id',
|
|
|
|
|
return_value=(app.id, build.versionCode, build.versionName),
|
|
|
|
|
):
|
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.is_apk_and_debuggable', return_value=False
|
|
|
|
|
):
|
2020-05-26 09:48:55 +02:00
|
|
|
|
fdroidserver.build.build_local(
|
2021-06-08 15:31:55 +02:00
|
|
|
|
app,
|
|
|
|
|
build,
|
|
|
|
|
vcs,
|
2022-11-22 17:17:45 +01:00
|
|
|
|
build_dir=self.testdir,
|
|
|
|
|
output_dir=self.testdir,
|
2021-06-08 15:31:55 +02:00
|
|
|
|
log_dir=None,
|
|
|
|
|
srclib_dir=None,
|
|
|
|
|
extlib_dir=None,
|
|
|
|
|
tmp_dir=None,
|
|
|
|
|
force=False,
|
|
|
|
|
onserver=False,
|
|
|
|
|
refresh=False,
|
2020-05-26 09:48:55 +02:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
self.assertTrue(os.path.exists('foo.aar'))
|
|
|
|
|
self.assertTrue(os.path.isdir('build'))
|
|
|
|
|
self.assertTrue(os.path.isdir('reports'))
|
|
|
|
|
self.assertTrue(os.path.isdir('target'))
|
2020-06-03 15:12:04 +02:00
|
|
|
|
self.assertFalse(os.path.exists('baz.so'))
|
2020-05-26 09:48:55 +02:00
|
|
|
|
self.assertFalse(os.path.exists('bin'))
|
|
|
|
|
self.assertFalse(os.path.exists('build/reports'))
|
|
|
|
|
self.assertFalse(os.path.exists('gen'))
|
|
|
|
|
self.assertFalse(os.path.exists('gradle-wrapper.jar'))
|
|
|
|
|
|
2020-06-30 02:47:53 +02:00
|
|
|
|
def test_scan_with_extlib(self):
|
2022-11-22 17:17:45 +01:00
|
|
|
|
os.chdir(self.testdir)
|
2020-06-30 02:47:53 +02:00
|
|
|
|
os.mkdir("build")
|
|
|
|
|
|
2022-09-28 17:35:31 +02:00
|
|
|
|
config = fdroidserver.common.get_config()
|
2020-06-30 02:47:53 +02:00
|
|
|
|
config['sdk_path'] = os.getenv('ANDROID_HOME')
|
|
|
|
|
config['ndk_paths'] = {'r10d': os.getenv('ANDROID_NDK_HOME')}
|
|
|
|
|
fdroidserver.common.config = config
|
|
|
|
|
app = fdroidserver.metadata.App()
|
|
|
|
|
app.id = 'com.gpl.rpg.AndorsTrail'
|
|
|
|
|
build = fdroidserver.metadata.Build()
|
|
|
|
|
build.commit = 'master'
|
|
|
|
|
build.androidupdate = ['no']
|
|
|
|
|
os.makedirs("extlib/android")
|
|
|
|
|
# write a fake binary jar file the scanner should definitely error on
|
|
|
|
|
with open('extlib/android/android-support-v4r11.jar', 'wb') as file:
|
2021-06-07 11:49:21 +02:00
|
|
|
|
file.write(
|
|
|
|
|
b'PK\x03\x04\x14\x00\x08\x00\x08\x00-\x0eiA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\x00\x04\x00META-INF/\xfe\xca\x00\x00\x03\x00PK\x07\x08\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00'
|
|
|
|
|
)
|
2020-06-30 02:47:53 +02:00
|
|
|
|
|
2021-06-07 11:49:21 +02:00
|
|
|
|
class FakeVcs:
|
2020-06-30 02:47:53 +02:00
|
|
|
|
# no need to change to the correct commit here
|
|
|
|
|
def gotorevision(self, rev, refresh=True):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def getsrclib(self):
|
|
|
|
|
return None
|
|
|
|
|
|
2023-11-13 16:31:56 +01:00
|
|
|
|
def deinitsubmodules(self):
|
|
|
|
|
pass
|
|
|
|
|
|
2020-08-18 22:33:12 +02:00
|
|
|
|
# Test we trigger a scanner error without extlibs
|
|
|
|
|
build.extlibs = []
|
|
|
|
|
os.makedirs('build/libs')
|
|
|
|
|
shutil.copy('extlib/android/android-support-v4r11.jar', 'build/libs')
|
2021-06-07 11:49:21 +02:00
|
|
|
|
fdroidserver.common.prepare_source(
|
|
|
|
|
FakeVcs(), app, build, "build", "ignore", "extlib"
|
|
|
|
|
)
|
2020-08-18 22:33:12 +02:00
|
|
|
|
count = fdroidserver.scanner.scan_source("build", build)
|
|
|
|
|
self.assertEqual(1, count, "Should produce a scanner error without extlib")
|
|
|
|
|
|
|
|
|
|
# Now try again as an extlib
|
|
|
|
|
build.extlibs = ['android/android-support-v4r11.jar']
|
2021-06-07 11:49:21 +02:00
|
|
|
|
fdroidserver.common.prepare_source(
|
|
|
|
|
FakeVcs(), app, build, "build", "ignore", "extlib"
|
|
|
|
|
)
|
2020-06-30 02:47:53 +02:00
|
|
|
|
count = fdroidserver.scanner.scan_source("build", build)
|
|
|
|
|
self.assertEqual(0, count, "Shouldn't error on jar from extlib")
|
|
|
|
|
|
2021-04-14 09:59:13 +02:00
|
|
|
|
def test_failed_verifies_are_not_in_unsigned(self):
|
2022-11-22 17:17:45 +01:00
|
|
|
|
os.chdir(self.testdir)
|
|
|
|
|
sdk_path = os.path.join(self.testdir, 'android-sdk')
|
2021-04-14 09:59:13 +02:00
|
|
|
|
self.create_fake_android_home(sdk_path)
|
2023-05-05 09:31:45 +02:00
|
|
|
|
with open('config.yml', 'w') as fp:
|
2023-05-05 09:27:46 +02:00
|
|
|
|
yaml.dump({'sdk_path': sdk_path, 'keep_when_not_allowed': True}, fp)
|
2023-05-05 09:31:45 +02:00
|
|
|
|
os.chmod('config.yml', 0o600)
|
2023-05-05 09:46:38 +02:00
|
|
|
|
fdroidserver.build.config = fdroidserver.common.read_config()
|
2023-05-05 09:31:45 +02:00
|
|
|
|
|
|
|
|
|
os.mkdir('metadata')
|
|
|
|
|
appid = 'info.guardianproject.checkey'
|
|
|
|
|
metadata_file = os.path.join('metadata', appid + '.yml')
|
|
|
|
|
shutil.copy(os.path.join(self.basedir, metadata_file), 'metadata')
|
|
|
|
|
with open(metadata_file) as fp:
|
|
|
|
|
app = fdroidserver.metadata.App(yaml.safe_load(fp))
|
|
|
|
|
app['RepoType'] = 'git'
|
|
|
|
|
app[
|
|
|
|
|
'Binaries'
|
|
|
|
|
] = 'https://example.com/fdroid/repo/info.guardianproject.checkey_%v.apk'
|
|
|
|
|
build = fdroidserver.metadata.Build(
|
|
|
|
|
{
|
|
|
|
|
'versionCode': 123,
|
|
|
|
|
'versionName': '1.2.3',
|
|
|
|
|
'commit': '1.2.3',
|
|
|
|
|
'disable': False,
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
app['Builds'] = [build]
|
|
|
|
|
fdroidserver.metadata.write_metadata(metadata_file, app)
|
|
|
|
|
|
|
|
|
|
os.makedirs(os.path.join('unsigned', 'binaries'))
|
|
|
|
|
production_result = os.path.join(
|
|
|
|
|
'unsigned', '%s_%d.apk' % (appid, build['versionCode'])
|
|
|
|
|
)
|
|
|
|
|
production_compare_file = os.path.join(
|
|
|
|
|
'unsigned', 'binaries', '%s_%d.binary.apk' % (appid, build['versionCode'])
|
|
|
|
|
)
|
|
|
|
|
os.makedirs(os.path.join('tmp', 'binaries'))
|
|
|
|
|
test_result = os.path.join('tmp', '%s_%d.apk' % (appid, build['versionCode']))
|
|
|
|
|
test_compare_file = os.path.join(
|
|
|
|
|
'tmp', 'binaries', '%s_%d.binary.apk' % (appid, build['versionCode'])
|
|
|
|
|
)
|
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.force_exit', lambda *args: None
|
|
|
|
|
) as a, mock.patch(
|
|
|
|
|
'fdroidserver.common.get_android_tools_version_log', lambda: 'fake'
|
|
|
|
|
) as b, mock.patch(
|
|
|
|
|
'fdroidserver.common.FDroidPopen', FakeProcess
|
|
|
|
|
) as c, mock.patch(
|
|
|
|
|
'fdroidserver.build.FDroidPopen', FakeProcess
|
|
|
|
|
) as d, mock.patch(
|
|
|
|
|
'fdroidserver.build.trybuild', lambda *args: True
|
|
|
|
|
) as e, mock.patch(
|
|
|
|
|
'fdroidserver.net.download_file', lambda *args, **kwargs: None
|
|
|
|
|
) as f:
|
|
|
|
|
a, b, c, d, e, f # silence linters' "unused" warnings
|
|
|
|
|
|
|
|
|
|
with mock.patch('sys.argv', ['fdroid build', appid]):
|
|
|
|
|
# successful comparison
|
|
|
|
|
open(production_result, 'w').close()
|
|
|
|
|
open(production_compare_file, 'w').close()
|
|
|
|
|
with mock.patch('fdroidserver.common.verify_apks', lambda *args: None):
|
|
|
|
|
fdroidserver.build.main()
|
|
|
|
|
self.assertTrue(os.path.exists(production_result))
|
|
|
|
|
self.assertTrue(os.path.exists(production_compare_file))
|
|
|
|
|
# failed comparison
|
|
|
|
|
open(production_result, 'w').close()
|
|
|
|
|
open(production_compare_file, 'w').close()
|
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.verify_apks', lambda *args: 'failed'
|
|
|
|
|
):
|
|
|
|
|
fdroidserver.build.main()
|
|
|
|
|
self.assertFalse(os.path.exists(production_result))
|
|
|
|
|
self.assertFalse(os.path.exists(production_compare_file))
|
|
|
|
|
|
|
|
|
|
with mock.patch('sys.argv', ['fdroid build', '--test', appid]):
|
|
|
|
|
# successful comparison
|
|
|
|
|
open(test_result, 'w').close()
|
|
|
|
|
open(test_compare_file, 'w').close()
|
|
|
|
|
with mock.patch('fdroidserver.common.verify_apks', lambda *args: None):
|
|
|
|
|
fdroidserver.build.main()
|
|
|
|
|
self.assertTrue(os.path.exists(test_result))
|
|
|
|
|
self.assertTrue(os.path.exists(test_compare_file))
|
|
|
|
|
self.assertFalse(os.path.exists(production_result))
|
|
|
|
|
self.assertFalse(os.path.exists(production_compare_file))
|
|
|
|
|
# failed comparison
|
|
|
|
|
open(test_result, 'w').close()
|
|
|
|
|
open(test_compare_file, 'w').close()
|
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.verify_apks', lambda *args: 'failed'
|
|
|
|
|
):
|
|
|
|
|
fdroidserver.build.main()
|
|
|
|
|
self.assertTrue(os.path.exists(test_result))
|
|
|
|
|
self.assertFalse(os.path.exists(test_compare_file))
|
|
|
|
|
self.assertFalse(os.path.exists(production_result))
|
|
|
|
|
self.assertFalse(os.path.exists(production_compare_file))
|
|
|
|
|
|
|
|
|
|
def test_failed_allowedapksigningkeys_are_not_in_unsigned(self):
|
|
|
|
|
os.chdir(self.testdir)
|
2021-04-14 09:59:13 +02:00
|
|
|
|
os.mkdir('metadata')
|
|
|
|
|
appid = 'info.guardianproject.checkey'
|
|
|
|
|
metadata_file = os.path.join('metadata', appid + '.yml')
|
2021-06-07 11:49:21 +02:00
|
|
|
|
shutil.copy(os.path.join(self.basedir, metadata_file), 'metadata')
|
2021-04-14 09:59:13 +02:00
|
|
|
|
with open(metadata_file) as fp:
|
|
|
|
|
app = fdroidserver.metadata.App(yaml.safe_load(fp))
|
|
|
|
|
app['RepoType'] = 'git'
|
2021-06-07 11:49:21 +02:00
|
|
|
|
app[
|
|
|
|
|
'Binaries'
|
|
|
|
|
] = 'https://example.com/fdroid/repo/info.guardianproject.checkey_%v.apk'
|
|
|
|
|
build = fdroidserver.metadata.Build(
|
|
|
|
|
{
|
|
|
|
|
'versionCode': 123,
|
|
|
|
|
'versionName': '1.2.3',
|
|
|
|
|
'commit': '1.2.3',
|
|
|
|
|
'disable': False,
|
|
|
|
|
}
|
|
|
|
|
)
|
2021-04-14 09:59:13 +02:00
|
|
|
|
app['Builds'] = [build]
|
2023-04-18 14:38:58 +02:00
|
|
|
|
expected_key = 'a' * 64
|
|
|
|
|
bogus_key = 'b' * 64
|
|
|
|
|
app['AllowedAPKSigningKeys'] = [expected_key]
|
2021-06-08 16:19:36 +02:00
|
|
|
|
fdroidserver.metadata.write_metadata(metadata_file, app)
|
2021-04-14 09:59:13 +02:00
|
|
|
|
|
|
|
|
|
os.makedirs(os.path.join('unsigned', 'binaries'))
|
2021-06-07 11:49:21 +02:00
|
|
|
|
production_result = os.path.join(
|
|
|
|
|
'unsigned', '%s_%d.apk' % (appid, build['versionCode'])
|
|
|
|
|
)
|
|
|
|
|
production_compare_file = os.path.join(
|
|
|
|
|
'unsigned', 'binaries', '%s_%d.binary.apk' % (appid, build['versionCode'])
|
|
|
|
|
)
|
2021-04-14 09:59:13 +02:00
|
|
|
|
os.makedirs(os.path.join('tmp', 'binaries'))
|
|
|
|
|
test_result = os.path.join('tmp', '%s_%d.apk' % (appid, build['versionCode']))
|
|
|
|
|
test_compare_file = os.path.join(
|
|
|
|
|
'tmp', 'binaries', '%s_%d.binary.apk' % (appid, build['versionCode'])
|
|
|
|
|
)
|
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.force_exit', lambda *args: None
|
|
|
|
|
) as a, mock.patch(
|
2021-05-26 17:35:39 +02:00
|
|
|
|
'fdroidserver.common.get_android_tools_version_log', lambda: 'fake'
|
2021-04-14 09:59:13 +02:00
|
|
|
|
) as b, mock.patch(
|
|
|
|
|
'fdroidserver.common.FDroidPopen', FakeProcess
|
|
|
|
|
) as c, mock.patch(
|
|
|
|
|
'fdroidserver.build.FDroidPopen', FakeProcess
|
|
|
|
|
) as d, mock.patch(
|
|
|
|
|
'fdroidserver.build.trybuild', lambda *args: True
|
|
|
|
|
) as e, mock.patch(
|
|
|
|
|
'fdroidserver.net.download_file', lambda *args, **kwargs: None
|
|
|
|
|
) as f:
|
|
|
|
|
a, b, c, d, e, f # silence linters' "unused" warnings
|
|
|
|
|
|
|
|
|
|
with mock.patch('sys.argv', ['fdroid build', appid]):
|
2023-04-18 14:38:58 +02:00
|
|
|
|
# successful comparison, successful signer
|
2021-04-14 09:59:13 +02:00
|
|
|
|
open(production_result, 'w').close()
|
|
|
|
|
open(production_compare_file, 'w').close()
|
2023-04-18 14:38:58 +02:00
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.verify_apks', lambda *args: None
|
|
|
|
|
) as g, mock.patch(
|
|
|
|
|
'fdroidserver.common.apk_signer_fingerprint',
|
|
|
|
|
lambda *args: expected_key,
|
|
|
|
|
) as h:
|
|
|
|
|
g, h
|
2021-04-14 09:59:13 +02:00
|
|
|
|
fdroidserver.build.main()
|
|
|
|
|
self.assertTrue(os.path.exists(production_result))
|
|
|
|
|
self.assertTrue(os.path.exists(production_compare_file))
|
2023-04-18 14:38:58 +02:00
|
|
|
|
# successful comparison, failed signer
|
|
|
|
|
open(production_result, 'w').close()
|
|
|
|
|
open(production_compare_file, 'w').close()
|
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.verify_apks', lambda *args: None
|
|
|
|
|
) as g, mock.patch(
|
|
|
|
|
'fdroidserver.common.apk_signer_fingerprint',
|
|
|
|
|
lambda *args: bogus_key,
|
|
|
|
|
) as h:
|
|
|
|
|
g, h
|
|
|
|
|
fdroidserver.build.main()
|
|
|
|
|
self.assertFalse(os.path.exists(production_result))
|
|
|
|
|
self.assertFalse(os.path.exists(production_compare_file))
|
2021-04-14 09:59:13 +02:00
|
|
|
|
# failed comparison
|
|
|
|
|
open(production_result, 'w').close()
|
|
|
|
|
open(production_compare_file, 'w').close()
|
2021-06-07 11:49:21 +02:00
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.verify_apks', lambda *args: 'failed'
|
|
|
|
|
):
|
2021-04-14 09:59:13 +02:00
|
|
|
|
fdroidserver.build.main()
|
|
|
|
|
self.assertFalse(os.path.exists(production_result))
|
|
|
|
|
self.assertFalse(os.path.exists(production_compare_file))
|
|
|
|
|
|
|
|
|
|
with mock.patch('sys.argv', ['fdroid build', '--test', appid]):
|
2023-04-18 14:38:58 +02:00
|
|
|
|
# successful comparison, successful signer
|
2021-04-14 09:59:13 +02:00
|
|
|
|
open(test_result, 'w').close()
|
|
|
|
|
open(test_compare_file, 'w').close()
|
2023-04-18 14:38:58 +02:00
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.verify_apks', lambda *args: None
|
|
|
|
|
) as g, mock.patch(
|
|
|
|
|
'fdroidserver.common.apk_signer_fingerprint',
|
|
|
|
|
lambda *args: expected_key,
|
|
|
|
|
) as h:
|
|
|
|
|
g, h
|
2021-04-14 09:59:13 +02:00
|
|
|
|
fdroidserver.build.main()
|
|
|
|
|
self.assertTrue(os.path.exists(test_result))
|
|
|
|
|
self.assertTrue(os.path.exists(test_compare_file))
|
|
|
|
|
self.assertFalse(os.path.exists(production_result))
|
|
|
|
|
self.assertFalse(os.path.exists(production_compare_file))
|
2023-04-18 14:38:58 +02:00
|
|
|
|
# successful comparison, failed signer
|
|
|
|
|
open(test_result, 'w').close()
|
|
|
|
|
open(test_compare_file, 'w').close()
|
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.verify_apks', lambda *args: None
|
|
|
|
|
) as g, mock.patch(
|
|
|
|
|
'fdroidserver.common.apk_signer_fingerprint',
|
|
|
|
|
lambda *args: bogus_key,
|
|
|
|
|
) as h:
|
|
|
|
|
g, h
|
|
|
|
|
fdroidserver.build.main()
|
|
|
|
|
self.assertTrue(os.path.exists(test_result))
|
|
|
|
|
self.assertFalse(os.path.exists(test_compare_file))
|
|
|
|
|
self.assertFalse(os.path.exists(production_result))
|
|
|
|
|
self.assertFalse(os.path.exists(production_compare_file))
|
2021-04-14 09:59:13 +02:00
|
|
|
|
# failed comparison
|
|
|
|
|
open(test_result, 'w').close()
|
|
|
|
|
open(test_compare_file, 'w').close()
|
2021-06-07 11:49:21 +02:00
|
|
|
|
with mock.patch(
|
|
|
|
|
'fdroidserver.common.verify_apks', lambda *args: 'failed'
|
|
|
|
|
):
|
2021-04-14 09:59:13 +02:00
|
|
|
|
fdroidserver.build.main()
|
|
|
|
|
self.assertTrue(os.path.exists(test_result))
|
|
|
|
|
self.assertFalse(os.path.exists(test_compare_file))
|
|
|
|
|
self.assertFalse(os.path.exists(production_result))
|
|
|
|
|
self.assertFalse(os.path.exists(production_compare_file))
|
|
|
|
|
|
2022-06-06 13:43:19 +02:00
|
|
|
|
@mock.patch('fdroidserver.vmtools.get_build_vm')
|
|
|
|
|
@mock.patch('fdroidserver.vmtools.get_clean_builder')
|
|
|
|
|
@mock.patch('paramiko.SSHClient')
|
|
|
|
|
@mock.patch('subprocess.check_output')
|
|
|
|
|
def test_build_server_cmdline(
|
|
|
|
|
self,
|
|
|
|
|
subprocess_check_output,
|
|
|
|
|
paramiko_SSHClient,
|
|
|
|
|
fdroidserver_vmtools_get_clean_builder,
|
|
|
|
|
fdroidserver_vmtools_get_build_vm,
|
|
|
|
|
):
|
|
|
|
|
"""Test command line flags passed to the buildserver"""
|
|
|
|
|
global cmdline_args
|
|
|
|
|
test_flag = ['', False]
|
|
|
|
|
|
|
|
|
|
def _exec_command(args):
|
|
|
|
|
flag = test_flag[0]
|
|
|
|
|
if test_flag[1]:
|
|
|
|
|
self.assertTrue(flag in args, flag + ' should be present')
|
|
|
|
|
else:
|
|
|
|
|
self.assertFalse(flag in args, flag + ' should not be present')
|
|
|
|
|
|
2022-11-22 17:17:45 +01:00
|
|
|
|
os.chdir(self.testdir)
|
2022-06-06 13:43:19 +02:00
|
|
|
|
os.mkdir('tmp')
|
|
|
|
|
|
|
|
|
|
chan = mock.MagicMock()
|
|
|
|
|
chan.exec_command = _exec_command
|
|
|
|
|
chan.recv_exit_status = lambda: 0
|
|
|
|
|
transport = mock.MagicMock()
|
|
|
|
|
transport.open_session = mock.Mock(return_value=chan)
|
|
|
|
|
sshs = mock.MagicMock()
|
|
|
|
|
sshs.get_transport = mock.Mock(return_value=transport)
|
|
|
|
|
paramiko_SSHClient.return_value = sshs
|
|
|
|
|
subprocess_check_output.return_value = (
|
|
|
|
|
b'0123456789abcdef0123456789abcdefcafebabe'
|
|
|
|
|
)
|
|
|
|
|
fdroidserver_vmtools_get_clean_builder.side_effect = lambda s: {
|
|
|
|
|
'hostname': 'example.com',
|
|
|
|
|
'idfile': '/path/to/id/file',
|
|
|
|
|
'port': 123,
|
|
|
|
|
'user': 'fake',
|
|
|
|
|
}
|
|
|
|
|
fdroidserver.common.config = {'sdk_path': '/fake/android/sdk/path'}
|
|
|
|
|
fdroidserver.build.options = mock.MagicMock()
|
|
|
|
|
vcs = mock.Mock()
|
|
|
|
|
vcs.getsrclib = mock.Mock(return_value=None)
|
|
|
|
|
app = fdroidserver.metadata.App()
|
|
|
|
|
app['metadatapath'] = 'metadata/fake.id.yml'
|
|
|
|
|
app['id'] = 'fake.id'
|
|
|
|
|
app['RepoType'] = 'git'
|
|
|
|
|
build = fdroidserver.metadata.Build(
|
|
|
|
|
{
|
|
|
|
|
'versionCode': 123,
|
|
|
|
|
'versionName': '1.2.3',
|
|
|
|
|
'commit': '1.2.3',
|
|
|
|
|
'disable': False,
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
app['Builds'] = [build]
|
|
|
|
|
|
|
|
|
|
test_flag = ('--on-server', True)
|
|
|
|
|
fdroidserver.build.build_server(app, build, vcs, '', '', '', False)
|
|
|
|
|
self.assertTrue(fdroidserver_vmtools_get_build_vm.called)
|
|
|
|
|
|
|
|
|
|
for force in (True, False):
|
|
|
|
|
test_flag = ('--force', force)
|
|
|
|
|
fdroidserver.build.build_server(app, build, vcs, '', '', '', force)
|
|
|
|
|
|
|
|
|
|
fdroidserver.build.options.notarball = True
|
|
|
|
|
test_flag = ('--no-tarball', True)
|
|
|
|
|
fdroidserver.build.build_server(app, build, vcs, '', '', '', False)
|
|
|
|
|
fdroidserver.build.options.notarball = False
|
|
|
|
|
test_flag = ('--no-tarball', False)
|
|
|
|
|
fdroidserver.build.build_server(app, build, vcs, '', '', '', False)
|
|
|
|
|
|
|
|
|
|
fdroidserver.build.options.skipscan = False
|
|
|
|
|
test_flag = ('--scan-binary', True)
|
|
|
|
|
fdroidserver.build.build_server(app, build, vcs, '', '', '', False)
|
|
|
|
|
fdroidserver.build.options.skipscan = True
|
|
|
|
|
test_flag = ('--scan-binary', False)
|
|
|
|
|
fdroidserver.build.build_server(app, build, vcs, '', '', '', False)
|
|
|
|
|
test_flag = ('--skip-scan', True)
|
|
|
|
|
fdroidserver.build.build_server(app, build, vcs, '', '', '', False)
|
|
|
|
|
|
2023-05-24 14:13:17 +02:00
|
|
|
|
@mock.patch('fdroidserver.vmtools.get_build_vm')
|
|
|
|
|
@mock.patch('fdroidserver.vmtools.get_clean_builder')
|
|
|
|
|
@mock.patch('paramiko.SSHClient')
|
|
|
|
|
@mock.patch('subprocess.check_output')
|
|
|
|
|
@mock.patch('fdroidserver.common.getsrclib')
|
|
|
|
|
@mock.patch('fdroidserver.common.prepare_source')
|
|
|
|
|
@mock.patch('fdroidserver.build.build_local')
|
|
|
|
|
@mock.patch('fdroidserver.common.get_android_tools_version_log', lambda: 'versions')
|
|
|
|
|
@mock.patch('fdroidserver.common.deploy_build_log_with_rsync', lambda a, b, c: None)
|
|
|
|
|
def test_build_server_no_local_prepare(
|
|
|
|
|
self,
|
|
|
|
|
build_build_local,
|
|
|
|
|
common_prepare_source,
|
|
|
|
|
common_getsrclib,
|
|
|
|
|
subprocess_check_output,
|
|
|
|
|
paramiko_SSHClient,
|
|
|
|
|
fdroidserver_vmtools_get_clean_builder,
|
|
|
|
|
fdroidserver_vmtools_get_build_vm,
|
|
|
|
|
):
|
|
|
|
|
"""srclibs Prepare: should only be executed in the buildserver"""
|
|
|
|
|
|
|
|
|
|
def _exec_command(args):
|
|
|
|
|
print('chan.exec_command', args)
|
|
|
|
|
|
|
|
|
|
def _getsrclib(
|
|
|
|
|
spec,
|
|
|
|
|
srclib_dir,
|
|
|
|
|
basepath=False,
|
|
|
|
|
raw=False,
|
|
|
|
|
prepare=True,
|
|
|
|
|
preponly=False,
|
|
|
|
|
refresh=True,
|
|
|
|
|
build=None,
|
|
|
|
|
):
|
|
|
|
|
name, ref = spec.split('@')
|
|
|
|
|
libdir = os.path.join(srclib_dir, name)
|
|
|
|
|
os.mkdir(libdir)
|
|
|
|
|
self.assertFalse(prepare, 'Prepare: scripts should never run on host')
|
|
|
|
|
return name, None, libdir # TODO
|
|
|
|
|
|
|
|
|
|
os.chdir(self.testdir)
|
|
|
|
|
|
|
|
|
|
chan = mock.MagicMock()
|
|
|
|
|
chan.exec_command = _exec_command
|
|
|
|
|
chan.recv_exit_status = lambda: 0
|
|
|
|
|
transport = mock.MagicMock()
|
|
|
|
|
transport.open_session = mock.Mock(return_value=chan)
|
|
|
|
|
sshs = mock.MagicMock()
|
|
|
|
|
sshs.get_transport = mock.Mock(return_value=transport)
|
|
|
|
|
paramiko_SSHClient.return_value = sshs
|
|
|
|
|
subprocess_check_output.return_value = (
|
|
|
|
|
b'0123456789abcdef0123456789abcdefcafebabe'
|
|
|
|
|
)
|
|
|
|
|
fdroidserver_vmtools_get_clean_builder.side_effect = lambda s: {
|
|
|
|
|
'hostname': 'example.com',
|
|
|
|
|
'idfile': '/path/to/id/file',
|
|
|
|
|
'port': 123,
|
|
|
|
|
'user': 'fake',
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fdroidserver.metadata.srclibs = {
|
|
|
|
|
'flutter': {
|
|
|
|
|
'RepoType': 'git',
|
|
|
|
|
'Repo': 'https://github.com/flutter/flutter',
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
os.mkdir('srclibs')
|
|
|
|
|
with open('srclibs/flutter.yml', 'w') as fp:
|
|
|
|
|
yaml.dump(fdroidserver.metadata.srclibs, fp)
|
|
|
|
|
common_getsrclib.side_effect = _getsrclib
|
|
|
|
|
|
|
|
|
|
options = mock.MagicMock()
|
|
|
|
|
options.force = False
|
|
|
|
|
options.notarball = True
|
|
|
|
|
options.onserver = False
|
|
|
|
|
options.refresh = False
|
|
|
|
|
options.scan_binary = False
|
|
|
|
|
options.server = True
|
|
|
|
|
options.skipscan = True
|
|
|
|
|
options.test = False
|
|
|
|
|
options.verbose = True
|
|
|
|
|
fdroidserver.build.options = options
|
|
|
|
|
fdroidserver.build.config = {'sdk_path': '/fake/android/sdk/path'}
|
|
|
|
|
|
|
|
|
|
vcs = mock.Mock()
|
|
|
|
|
vcs.getsrclib = mock.Mock(return_value=None)
|
|
|
|
|
app = fdroidserver.metadata.App()
|
|
|
|
|
app['metadatapath'] = 'metadata/fake.id.yml'
|
|
|
|
|
app['id'] = 'fake.id'
|
|
|
|
|
app['RepoType'] = 'git'
|
|
|
|
|
spec = 'flutter@v1.7.8'
|
|
|
|
|
build = fdroidserver.metadata.Build(
|
|
|
|
|
{
|
|
|
|
|
'versionCode': 123,
|
|
|
|
|
'versionName': '1.2.3',
|
|
|
|
|
'commit': '1.2.3',
|
|
|
|
|
'disable': False,
|
|
|
|
|
'srclibs': [spec],
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
app['Builds'] = [build]
|
|
|
|
|
|
|
|
|
|
build_dir = 'build'
|
|
|
|
|
srclib_dir = os.path.join(build_dir, 'srclib')
|
|
|
|
|
extlib_dir = os.path.join(build_dir, 'extlib')
|
|
|
|
|
os.mkdir('tmp')
|
|
|
|
|
os.mkdir(build_dir)
|
|
|
|
|
os.mkdir(srclib_dir)
|
|
|
|
|
|
|
|
|
|
fdroidserver.build.trybuild(
|
|
|
|
|
app,
|
|
|
|
|
build,
|
|
|
|
|
build_dir,
|
|
|
|
|
'unsigned',
|
|
|
|
|
'logs',
|
|
|
|
|
None,
|
|
|
|
|
srclib_dir,
|
|
|
|
|
extlib_dir,
|
|
|
|
|
'tmp',
|
|
|
|
|
'repo',
|
|
|
|
|
vcs,
|
|
|
|
|
options.test,
|
|
|
|
|
options.server,
|
|
|
|
|
options.force,
|
|
|
|
|
options.onserver,
|
|
|
|
|
options.refresh,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
common_getsrclib.assert_called_once_with(
|
|
|
|
|
spec, srclib_dir, basepath=True, prepare=False
|
|
|
|
|
)
|
|
|
|
|
common_prepare_source.assert_not_called()
|
|
|
|
|
build_build_local.assert_not_called()
|
|
|
|
|
|
2023-05-05 09:27:46 +02:00
|
|
|
|
def test_keep_when_not_allowed_default(self):
|
|
|
|
|
self.assertFalse(fdroidserver.build.keep_when_not_allowed())
|
|
|
|
|
|
|
|
|
|
def test_keep_when_not_allowed_config_true(self):
|
|
|
|
|
fdroidserver.build.config = {'keep_when_not_allowed': True}
|
|
|
|
|
self.assertTrue(fdroidserver.build.keep_when_not_allowed())
|
|
|
|
|
|
|
|
|
|
def test_keep_when_not_allowed_config_false(self):
|
|
|
|
|
fdroidserver.build.config = {'keep_when_not_allowed': False}
|
|
|
|
|
self.assertFalse(fdroidserver.build.keep_when_not_allowed())
|
|
|
|
|
|
|
|
|
|
def test_keep_when_not_allowed_options_true(self):
|
|
|
|
|
fdroidserver.build.options = Options
|
|
|
|
|
fdroidserver.build.options.keep_when_not_allowed = True
|
|
|
|
|
self.assertTrue(fdroidserver.build.keep_when_not_allowed())
|
|
|
|
|
|
|
|
|
|
def test_keep_when_not_allowed_options_false(self):
|
|
|
|
|
fdroidserver.build.options = Options
|
|
|
|
|
fdroidserver.build.options.keep_when_not_allowed = False
|
|
|
|
|
self.assertFalse(fdroidserver.build.keep_when_not_allowed())
|
|
|
|
|
|
|
|
|
|
def test_keep_when_not_allowed_options_true_override_config(self):
|
|
|
|
|
fdroidserver.build.options = Options
|
|
|
|
|
fdroidserver.build.options.keep_when_not_allowed = True
|
|
|
|
|
fdroidserver.build.config = {'keep_when_not_allowed': False}
|
|
|
|
|
self.assertTrue(fdroidserver.build.keep_when_not_allowed())
|
|
|
|
|
|
|
|
|
|
def test_keep_when_not_allowed_options_default_does_not_override(self):
|
|
|
|
|
fdroidserver.build.options = Options
|
|
|
|
|
fdroidserver.build.options.keep_when_not_allowed = False
|
|
|
|
|
fdroidserver.build.config = {'keep_when_not_allowed': True}
|
|
|
|
|
self.assertTrue(fdroidserver.build.keep_when_not_allowed())
|
|
|
|
|
|
|
|
|
|
def test_keep_when_not_allowed_all_true(self):
|
|
|
|
|
fdroidserver.build.options = Options
|
|
|
|
|
fdroidserver.build.options.keep_when_not_allowed = True
|
|
|
|
|
fdroidserver.build.config = {'keep_when_not_allowed': True}
|
|
|
|
|
self.assertTrue(fdroidserver.build.keep_when_not_allowed())
|
|
|
|
|
|
|
|
|
|
def test_keep_when_not_allowed_all_false(self):
|
|
|
|
|
fdroidserver.build.options = Options
|
|
|
|
|
fdroidserver.build.options.keep_when_not_allowed = False
|
|
|
|
|
fdroidserver.build.config = {'keep_when_not_allowed': False}
|
|
|
|
|
self.assertFalse(fdroidserver.build.keep_when_not_allowed())
|
|
|
|
|
|
2016-06-20 20:00:59 +02:00
|
|
|
|
|
2015-07-30 22:13:36 +02:00
|
|
|
|
if __name__ == "__main__":
|
2018-08-14 10:10:19 +02:00
|
|
|
|
os.chdir(os.path.dirname(__file__))
|
|
|
|
|
|
2015-07-30 22:13:36 +02:00
|
|
|
|
parser = optparse.OptionParser()
|
2021-06-07 11:49:21 +02:00
|
|
|
|
parser.add_option(
|
|
|
|
|
"-v",
|
|
|
|
|
"--verbose",
|
|
|
|
|
action="store_true",
|
|
|
|
|
default=False,
|
|
|
|
|
help="Spew out even more information than normal",
|
|
|
|
|
)
|
2015-07-30 22:13:36 +02:00
|
|
|
|
(fdroidserver.common.options, args) = parser.parse_args(['--verbose'])
|
|
|
|
|
|
|
|
|
|
newSuite = unittest.TestSuite()
|
|
|
|
|
newSuite.addTest(unittest.makeSuite(BuildTest))
|
2017-10-20 11:51:59 +02:00
|
|
|
|
unittest.main(failfast=False)
|