diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/mozbase/mozinstall | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | testing/mozbase/mozinstall/mozinstall/__init__.py | 6 | ||||
-rw-r--r-- | testing/mozbase/mozinstall/mozinstall/mozinstall.py | 443 | ||||
-rw-r--r-- | testing/mozbase/mozinstall/setup.cfg | 2 | ||||
-rw-r--r-- | testing/mozbase/mozinstall/setup.py | 59 | ||||
-rw-r--r-- | testing/mozbase/mozinstall/tests/conftest.py | 14 | ||||
-rw-r--r-- | testing/mozbase/mozinstall/tests/installer_stubs/firefox.dmg | bin | 0 -> 27309 bytes | |||
-rw-r--r-- | testing/mozbase/mozinstall/tests/installer_stubs/firefox.tar.bz2 | bin | 0 -> 2882 bytes | |||
-rw-r--r-- | testing/mozbase/mozinstall/tests/installer_stubs/firefox.zip | bin | 0 -> 8707 bytes | |||
-rw-r--r-- | testing/mozbase/mozinstall/tests/manifest.ini | 8 | ||||
-rw-r--r-- | testing/mozbase/mozinstall/tests/test_binary.py | 50 | ||||
-rw-r--r-- | testing/mozbase/mozinstall/tests/test_install.py | 90 | ||||
-rw-r--r-- | testing/mozbase/mozinstall/tests/test_is_installer.py | 40 | ||||
-rw-r--r-- | testing/mozbase/mozinstall/tests/test_uninstall.py | 39 |
13 files changed, 751 insertions, 0 deletions
diff --git a/testing/mozbase/mozinstall/mozinstall/__init__.py b/testing/mozbase/mozinstall/mozinstall/__init__.py new file mode 100644 index 0000000000..09c6d10a3d --- /dev/null +++ b/testing/mozbase/mozinstall/mozinstall/__init__.py @@ -0,0 +1,6 @@ +# flake8: noqa +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +from .mozinstall import * diff --git a/testing/mozbase/mozinstall/mozinstall/mozinstall.py b/testing/mozbase/mozinstall/mozinstall/mozinstall.py new file mode 100644 index 0000000000..d966b258ed --- /dev/null +++ b/testing/mozbase/mozinstall/mozinstall/mozinstall.py @@ -0,0 +1,443 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import plistlib +import shutil +import subprocess +import sys +import tarfile +import tempfile +import time +import zipfile +from optparse import OptionParser + +import mozfile +import mozinfo +import requests +from six import PY3, reraise + +try: + import pefile + + has_pefile = True +except ImportError: + has_pefile = False + + +TIMEOUT_UNINSTALL = 60 + + +class InstallError(Exception): + """Thrown when installation fails. Includes traceback if available.""" + + +class InvalidBinary(Exception): + """Thrown when the binary cannot be found after the installation.""" + + +class InvalidSource(Exception): + """Thrown when the specified source is not a recognized file type. + + Supported types: + Linux: tar.gz, tar.bz2 + Mac: dmg + Windows: zip, exe + + """ + + +class UninstallError(Exception): + """Thrown when uninstallation fails. Includes traceback if available.""" + + +def _readPlist(path): + if PY3: + with open(path, "rb") as fp: + return plistlib.load(fp) + return plistlib.readPlist(path) + + +def get_binary(path, app_name): + """Find the binary in the specified path, and return its path. If binary is + not found throw an InvalidBinary exception. + + :param path: Path within to search for the binary + :param app_name: Application binary without file extension to look for + """ + binary = None + + # On OS X we can get the real binary from the app bundle + if mozinfo.isMac: + plist = "%s/Contents/Info.plist" % path + if not os.path.isfile(plist): + raise InvalidBinary("%s/Contents/Info.plist not found" % path) + + binary = os.path.join( + path, "Contents/MacOS/", _readPlist(plist)["CFBundleExecutable"] + ) + + else: + app_name = app_name.lower() + + if mozinfo.isWin: + app_name = app_name + ".exe" + + for root, dirs, files in os.walk(path): + for filename in files: + # os.access evaluates to False for some reason, so not using it + if filename.lower() == app_name: + binary = os.path.realpath(os.path.join(root, filename)) + break + + if not binary: + # The expected binary has not been found. + raise InvalidBinary('"%s" does not contain a valid binary.' % path) + + return binary + + +def install(src, dest): + """Install a zip, exe, tar.gz, tar.bz2 or dmg file, and return the path of + the installation folder. + + :param src: Path to the install file + :param dest: Path to install to (to ensure we do not overwrite any existent + files the folder should not exist yet) + """ + if not is_installer(src): + msg = "{} is not a valid installer file".format(src) + if "://" in src: + try: + return _install_url(src, dest) + except Exception: + exc, val, tb = sys.exc_info() + error = InvalidSource("{} ({})".format(msg, val)) + reraise(InvalidSource, error, tb) + raise InvalidSource(msg) + + src = os.path.realpath(src) + dest = os.path.realpath(dest) + + did_we_create = False + if not os.path.exists(dest): + did_we_create = True + os.makedirs(dest) + + trbk = None + try: + install_dir = None + if src.lower().endswith(".dmg"): + install_dir = _install_dmg(src, dest) + elif src.lower().endswith(".exe"): + install_dir = _install_exe(src, dest) + elif src.lower().endswith(".msix"): + install_dir = _install_msix(src) + elif zipfile.is_zipfile(src) or tarfile.is_tarfile(src): + install_dir = mozfile.extract(src, dest)[0] + + return install_dir + + except BaseException: + cls, exc, trbk = sys.exc_info() + if did_we_create: + try: + # try to uninstall this properly + uninstall(dest) + except Exception: + # uninstall may fail, let's just try to clean the folder + # in this case + try: + mozfile.remove(dest) + except Exception: + pass + if issubclass(cls, Exception): + error = InstallError('Failed to install "%s (%s)"' % (src, str(exc))) + reraise(InstallError, error, trbk) + # any other kind of exception like KeyboardInterrupt is just re-raised. + reraise(cls, exc, trbk) + + finally: + # trbk won't get GC'ed due to circular reference + # http://docs.python.org/library/sys.html#sys.exc_info + del trbk + + +def is_installer(src): + """Tests if the given file is a valid installer package. + + Supported types: + Linux: tar.gz, tar.bz2 + Mac: dmg + Windows: zip, exe + + On Windows pefile will be used to determine if the executable is the + right type, if it is installed on the system. + + :param src: Path to the install file. + """ + src = os.path.realpath(src) + + if not os.path.isfile(src): + return False + + if mozinfo.isLinux: + return tarfile.is_tarfile(src) + elif mozinfo.isMac: + return src.lower().endswith(".dmg") + elif mozinfo.isWin: + if zipfile.is_zipfile(src): + return True + + if os.access(src, os.X_OK) and src.lower().endswith(".exe"): + if has_pefile: + # try to determine if binary is actually a gecko installer + pe_data = pefile.PE(src) + data = {} + for info in getattr(pe_data, "FileInfo", []): + if info.Key == "StringFileInfo": + for string in info.StringTable: + data.update(string.entries) + return "BuildID" not in data + else: + # pefile not available, just assume a proper binary was passed in + return True + + return False + + +def uninstall(install_folder): + """Uninstalls the application in the specified path. If it has been + installed via an installer on Windows, use the uninstaller first. + + :param install_folder: Path of the installation folder + + """ + # Uninstallation for MSIX applications is totally different than + # any other installs... + if "WindowsApps" in install_folder: + # At the time of writing, the package installation directory is always + # the package full name, so this assumption is valid (for now....). + packageFullName = install_folder.split("WindowsApps\\")[1].split("\\")[0] + cmd = f"powershell.exe Remove-AppxPackage -Package {packageFullName}" + subprocess.check_call(cmd) + return + + install_folder = os.path.realpath(install_folder) + assert os.path.isdir(install_folder), ( + 'installation folder "%s" exists.' % install_folder + ) + + # On Windows we have to use the uninstaller. If it's not available fallback + # to the directory removal code + if mozinfo.isWin: + uninstall_folder = "%s\\uninstall" % install_folder + log_file = "%s\\uninstall.log" % uninstall_folder + + if os.path.isfile(log_file): + trbk = None + try: + cmdArgs = ["%s\\uninstall\helper.exe" % install_folder, "/S"] + result = subprocess.call(cmdArgs) + if result != 0: + raise Exception("Execution of uninstaller failed.") + + # The uninstaller spawns another process so the subprocess call + # returns immediately. We have to wait until the uninstall + # folder has been removed or until we run into a timeout. + end_time = time.time() + TIMEOUT_UNINSTALL + while os.path.exists(uninstall_folder): + time.sleep(1) + + if time.time() > end_time: + raise Exception("Failure removing uninstall folder.") + + except Exception as ex: + cls, exc, trbk = sys.exc_info() + error = UninstallError( + "Failed to uninstall %s (%s)" % (install_folder, str(ex)) + ) + reraise(UninstallError, error, trbk) + + finally: + # trbk won't get GC'ed due to circular reference + # http://docs.python.org/library/sys.html#sys.exc_info + del trbk + + # Ensure that we remove any trace of the installation. Even the uninstaller + # on Windows leaves files behind we have to explicitely remove. + mozfile.remove(install_folder) + + +def _install_url(url, dest): + """Saves a url to a temporary file, and passes that through to the + install function. + + :param url: Url to the install file + :param dest: Path to install to (to ensure we do not overwrite any existent + files the folder should not exist yet) + """ + r = requests.get(url, stream=True) + name = tempfile.mkstemp()[1] + try: + with open(name, "w+b") as fh: + for chunk in r.iter_content(chunk_size=16 * 1024): + fh.write(chunk) + result = install(name, dest) + finally: + mozfile.remove(name) + return result + + +def _install_dmg(src, dest): + """Extract a dmg file into the destination folder and return the + application folder. + + src -- DMG image which has to be extracted + dest -- the path to extract to + + """ + appDir = None + try: + # According to the Apple doc, the hdiutil output is stable and is based on the tab + # separators + # Therefor, $3 should give us the mounted path + appDir = ( + subprocess.check_output( + 'hdiutil attach -nobrowse -noautoopen "%s"' + "|grep /Volumes/" + "|awk 'BEGIN{FS=\"\t\"} {print $3}'" % str(src), + shell=True, + ) + .strip() + .decode("ascii") + ) + + for appFile in os.listdir(appDir): + if appFile.endswith(".app"): + appName = appFile + break + + mounted_path = os.path.join(appDir, appName) + + dest = os.path.join(dest, appName) + + # copytree() would fail if dest already exists. + if os.path.exists(dest): + raise InstallError('App bundle "%s" already exists.' % dest) + + shutil.copytree(mounted_path, dest, False) + + finally: + if appDir: + subprocess.check_call('hdiutil detach "%s" -quiet' % appDir, shell=True) + + return dest + + +def _install_exe(src, dest): + """Run the MSI installer to silently install the application into the + destination folder. Return the folder path. + + Arguments: + src -- MSI installer to be executed + dest -- the path to install to + + """ + # The installer doesn't automatically create a sub folder. Lets guess the + # best name from the src file name + filename = os.path.basename(src) + dest = os.path.join(dest, filename.split(".")[0]) + + # possibly gets around UAC in vista (still need to run as administrator) + os.environ["__compat_layer"] = "RunAsInvoker" + cmd = '"%s" /extractdir=%s' % (src, os.path.realpath(dest)) + + subprocess.check_call(cmd) + + return dest + + +def _get_msix_install_location(pkg): + with zipfile.ZipFile(pkg) as zf: + # First, we pull the app identity out of the AppxManifest... + with zf.open("AppxManifest.xml") as am: + for line in am.readlines(): + line = line.decode("utf-8") + if "<Identity" in line: + for part in line.split(" "): + if part.startswith("Name"): + pkgname = part.split("=")[-1].strip('"\r\n') + + # ...then we can use it to find the install location + # with this cmdlet + cmd = ( + f'powershell.exe "Get-AppxPackage" "-Name" "{pkgname}"' + ) + for line in ( + subprocess.check_output(cmd) + .decode("utf-8") + .splitlines() + ): + if line.startswith("InstallLocation"): + return "C:{}".format(line.split(":")[-1].strip()) + + raise Exception(f"Couldn't find install location of {pkg}") + + +def _install_msix(src): + """Install the MSIX package and return the installation path. + + Arguments: + src -- MSIX package to install + + """ + # possibly gets around UAC in vista (still need to run as administrator) + cmd = f'powershell.exe "Add-AppxPackage" "-Path" "{src}"' + subprocess.check_call(cmd) + + return _get_msix_install_location(src) + + +def install_cli(argv=sys.argv[1:]): + parser = OptionParser(usage="usage: %prog [options] installer") + parser.add_option( + "-d", + "--destination", + dest="dest", + default=os.getcwd(), + help="Directory to install application into. " '[default: "%default"]', + ) + parser.add_option( + "--app", + dest="app", + default="firefox", + help="Application being installed. [default: %default]", + ) + + (options, args) = parser.parse_args(argv) + if not len(args) == 1: + parser.error("An installer file has to be specified.") + + src = args[0] + + # Run it + if os.path.isdir(src): + binary = get_binary(src, app_name=options.app) + else: + install_path = install(src, options.dest) + binary = get_binary(install_path, app_name=options.app) + + print(binary) + + +def uninstall_cli(argv=sys.argv[1:]): + parser = OptionParser(usage="usage: %prog install_path") + + (options, args) = parser.parse_args(argv) + if not len(args) == 1: + parser.error("An installation path has to be specified.") + + # Run it + uninstall(argv[0]) diff --git a/testing/mozbase/mozinstall/setup.cfg b/testing/mozbase/mozinstall/setup.cfg new file mode 100644 index 0000000000..2a9acf13da --- /dev/null +++ b/testing/mozbase/mozinstall/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal = 1 diff --git a/testing/mozbase/mozinstall/setup.py b/testing/mozbase/mozinstall/setup.py new file mode 100644 index 0000000000..dbcf2a1c19 --- /dev/null +++ b/testing/mozbase/mozinstall/setup.py @@ -0,0 +1,59 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +import os + +from setuptools import setup + +try: + here = os.path.dirname(os.path.abspath(__file__)) + description = open(os.path.join(here, "README.md")).read() +except IOError: + description = None + +PACKAGE_VERSION = "2.0.1" + +deps = [ + "mozinfo >= 0.7", + "mozfile >= 1.0", + "requests", + "six >= 1.13.0", +] + +setup( + name="mozInstall", + version=PACKAGE_VERSION, + description="package for installing and uninstalling Mozilla applications", + long_description="see https://firefox-source-docs.mozilla.org/mozbase/index.html", + # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", + "Natural Language :: English", + "Operating System :: OS Independent", + "Topic :: Software Development :: Libraries :: Python Modules", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + ], + keywords="mozilla", + author="Mozilla Automation and Tools team", + author_email="tools@lists.mozilla.org", + url="https://wiki.mozilla.org/Auto-tools/Projects/Mozbase", + license="MPL 2.0", + packages=["mozinstall"], + include_package_data=True, + zip_safe=False, + install_requires=deps, + # we have to generate two more executables for those systems that cannot run as Administrator + # and the filename containing "install" triggers the UAC + entry_points=""" + # -*- Entry points: -*- + [console_scripts] + mozinstall = mozinstall:install_cli + mozuninstall = mozinstall:uninstall_cli + moz_add_to_system = mozinstall:install_cli + moz_remove_from_system = mozinstall:uninstall_cli + """, +) diff --git a/testing/mozbase/mozinstall/tests/conftest.py b/testing/mozbase/mozinstall/tests/conftest.py new file mode 100644 index 0000000000..132547a96b --- /dev/null +++ b/testing/mozbase/mozinstall/tests/conftest.py @@ -0,0 +1,14 @@ +import pytest + + +@pytest.fixture +def get_installer(request): + def _get_installer(extension): + """Get path to the installer for the specified extension.""" + stub_dir = request.node.fspath.dirpath("installer_stubs") + + # We had to remove firefox.exe since it is not valid for mozinstall 1.12 and higher + # Bug 1157352 - We should grab a firefox.exe from the build process or download it + return stub_dir.join("firefox.{}".format(extension)).strpath + + return _get_installer diff --git a/testing/mozbase/mozinstall/tests/installer_stubs/firefox.dmg b/testing/mozbase/mozinstall/tests/installer_stubs/firefox.dmg Binary files differnew file mode 100644 index 0000000000..dd9c779dfa --- /dev/null +++ b/testing/mozbase/mozinstall/tests/installer_stubs/firefox.dmg diff --git a/testing/mozbase/mozinstall/tests/installer_stubs/firefox.tar.bz2 b/testing/mozbase/mozinstall/tests/installer_stubs/firefox.tar.bz2 Binary files differnew file mode 100644 index 0000000000..cb046a0e7f --- /dev/null +++ b/testing/mozbase/mozinstall/tests/installer_stubs/firefox.tar.bz2 diff --git a/testing/mozbase/mozinstall/tests/installer_stubs/firefox.zip b/testing/mozbase/mozinstall/tests/installer_stubs/firefox.zip Binary files differnew file mode 100644 index 0000000000..7c3f61a5e9 --- /dev/null +++ b/testing/mozbase/mozinstall/tests/installer_stubs/firefox.zip diff --git a/testing/mozbase/mozinstall/tests/manifest.ini b/testing/mozbase/mozinstall/tests/manifest.ini new file mode 100644 index 0000000000..d5e0d06976 --- /dev/null +++ b/testing/mozbase/mozinstall/tests/manifest.ini @@ -0,0 +1,8 @@ +[DEFAULT] +subsuite = mozbase +[test_binary.py] +skip-if = os == 'mac' +[test_install.py] +skip-if = os == 'mac' # intermittent +[test_is_installer.py] +[test_uninstall.py] diff --git a/testing/mozbase/mozinstall/tests/test_binary.py b/testing/mozbase/mozinstall/tests/test_binary.py new file mode 100644 index 0000000000..6454c78ef5 --- /dev/null +++ b/testing/mozbase/mozinstall/tests/test_binary.py @@ -0,0 +1,50 @@ +import os + +import mozinfo +import mozinstall +import mozunit +import pytest + + +@pytest.mark.skipif( + mozinfo.isWin, + reason="Bug 1157352 - New firefox.exe needed for mozinstall 1.12 and higher.", +) +def test_get_binary(tmpdir, get_installer): + """Test to retrieve binary from install path.""" + if mozinfo.isLinux: + installdir = mozinstall.install(get_installer("tar.bz2"), tmpdir.strpath) + binary = os.path.join(installdir, "firefox") + + assert mozinstall.get_binary(installdir, "firefox") == binary + + elif mozinfo.isWin: + installdir_exe = mozinstall.install( + get_installer("exe"), tmpdir.join("exe").strpath + ) + binary_exe = os.path.join(installdir_exe, "core", "firefox.exe") + + assert mozinstall.get_binary(installdir_exe, "firefox") == binary_exe + + installdir_zip = mozinstall.install( + get_installer("zip"), tmpdir.join("zip").strpath + ) + binary_zip = os.path.join(installdir_zip, "firefox.exe") + + assert mozinstall.get_binary(installdir_zip, "firefox") == binary_zip + + elif mozinfo.isMac: + installdir = mozinstall.install(get_installer("dmg"), tmpdir.strpath) + binary = os.path.join(installdir, "Contents", "MacOS", "firefox") + + assert mozinstall.get_binary(installdir, "firefox") == binary + + +def test_get_binary_error(tmpdir): + """Test that an InvalidBinary error is raised.""" + with pytest.raises(mozinstall.InvalidBinary): + mozinstall.get_binary(tmpdir.strpath, "firefox") + + +if __name__ == "__main__": + mozunit.main() diff --git a/testing/mozbase/mozinstall/tests/test_install.py b/testing/mozbase/mozinstall/tests/test_install.py new file mode 100644 index 0000000000..2dceb2cc78 --- /dev/null +++ b/testing/mozbase/mozinstall/tests/test_install.py @@ -0,0 +1,90 @@ +import subprocess + +import mozinfo +import mozinstall +import mozunit +import pytest + + +@pytest.mark.skipif( + mozinfo.isWin, + reason="Bug 1157352 - New firefox.exe needed for mozinstall 1.12 and higher.", +) +def test_is_installer(request, get_installer): + """Test that we can identify a correct installer.""" + if mozinfo.isLinux: + assert mozinstall.is_installer(get_installer("tar.bz2")) + + if mozinfo.isWin: + # test zip installer + assert mozinstall.is_installer(get_installer("zip")) + + # test exe installer + assert mozinstall.is_installer(get_installer("exe")) + + try: + # test stub browser file + # without pefile on the system this test will fail + import pefile # noqa + + stub_exe = ( + request.node.fspath.dirpath("build_stub").join("firefox.exe").strpath + ) + assert not mozinstall.is_installer(stub_exe) + except ImportError: + pass + + if mozinfo.isMac: + assert mozinstall.is_installer(get_installer("dmg")) + + +def test_invalid_source_error(get_installer): + """Test that InvalidSource error is raised with an incorrect installer.""" + if mozinfo.isLinux: + with pytest.raises(mozinstall.InvalidSource): + mozinstall.install(get_installer("dmg"), "firefox") + + elif mozinfo.isWin: + with pytest.raises(mozinstall.InvalidSource): + mozinstall.install(get_installer("tar.bz2"), "firefox") + + elif mozinfo.isMac: + with pytest.raises(mozinstall.InvalidSource): + mozinstall.install(get_installer("tar.bz2"), "firefox") + + # Test an invalid url handler + with pytest.raises(mozinstall.InvalidSource): + mozinstall.install("file://foo.bar", "firefox") + + +@pytest.mark.skipif( + mozinfo.isWin, + reason="Bug 1157352 - New firefox.exe needed for mozinstall 1.12 and higher.", +) +def test_install(tmpdir, get_installer): + """Test to install an installer.""" + if mozinfo.isLinux: + installdir = mozinstall.install(get_installer("tar.bz2"), tmpdir.strpath) + assert installdir == tmpdir.join("firefox").strpath + + elif mozinfo.isWin: + installdir_exe = mozinstall.install( + get_installer("exe"), tmpdir.join("exe").strpath + ) + assert installdir_exe == tmpdir.join("exe", "firefox").strpath + + installdir_zip = mozinstall.install( + get_installer("zip"), tmpdir.join("zip").strpath + ) + assert installdir_zip == tmpdir.join("zip", "firefox").strpath + + elif mozinfo.isMac: + installdir = mozinstall.install(get_installer("dmg"), tmpdir.strpath) + assert installdir == tmpdir.realpath().join("Firefox Stub.app").strpath + + mounted_images = subprocess.check_output(["hdiutil", "info"]).decode("ascii") + assert get_installer("dmg") not in mounted_images + + +if __name__ == "__main__": + mozunit.main() diff --git a/testing/mozbase/mozinstall/tests/test_is_installer.py b/testing/mozbase/mozinstall/tests/test_is_installer.py new file mode 100644 index 0000000000..057c29f968 --- /dev/null +++ b/testing/mozbase/mozinstall/tests/test_is_installer.py @@ -0,0 +1,40 @@ +import mozinfo +import mozinstall +import mozunit +import pytest + + +@pytest.mark.skipif( + mozinfo.isWin, + reason="Bug 1157352 - New firefox.exe needed for mozinstall 1.12 and higher.", +) +def test_is_installer(request, get_installer): + """Test that we can identify a correct installer.""" + if mozinfo.isLinux: + assert mozinstall.is_installer(get_installer("tar.bz2")) + + if mozinfo.isWin: + # test zip installer + assert mozinstall.is_installer(get_installer("zip")) + + # test exe installer + assert mozinstall.is_installer(get_installer("exe")) + + try: + # test stub browser file + # without pefile on the system this test will fail + import pefile # noqa + + stub_exe = ( + request.node.fspath.dirpath("build_stub").join("firefox.exe").strpath + ) + assert not mozinstall.is_installer(stub_exe) + except ImportError: + pass + + if mozinfo.isMac: + assert mozinstall.is_installer(get_installer("dmg")) + + +if __name__ == "__main__": + mozunit.main() diff --git a/testing/mozbase/mozinstall/tests/test_uninstall.py b/testing/mozbase/mozinstall/tests/test_uninstall.py new file mode 100644 index 0000000000..45298a834d --- /dev/null +++ b/testing/mozbase/mozinstall/tests/test_uninstall.py @@ -0,0 +1,39 @@ +import mozinfo +import mozinstall +import mozunit +import py +import pytest + + +@pytest.mark.skipif( + mozinfo.isWin, + reason="Bug 1157352 - New firefox.exe needed for mozinstall 1.12 and higher.", +) +def test_uninstall(tmpdir, get_installer): + """Test to uninstall an installed binary.""" + if mozinfo.isLinux: + installdir = mozinstall.install(get_installer("tar.bz2"), tmpdir.strpath) + mozinstall.uninstall(installdir) + assert not py.path.local(installdir).check() + + elif mozinfo.isWin: + installdir_exe = mozinstall.install( + get_installer("exe"), tmpdir.join("exe").strpath + ) + mozinstall.uninstall(installdir_exe) + assert not py.path.local(installdir).check() + + installdir_zip = mozinstall.install( + get_installer("zip"), tmpdir.join("zip").strpath + ) + mozinstall.uninstall(installdir_zip) + assert not py.path.local(installdir).check() + + elif mozinfo.isMac: + installdir = mozinstall.install(get_installer("dmg"), tmpdir.strpath) + mozinstall.uninstall(installdir) + assert not py.path.local(installdir).check() + + +if __name__ == "__main__": + mozunit.main() |