Files
cef/libcef_dll/bootstrap/installer/e2e/test_exit_codes.py
T
Marshall Greenblatt be20927a8d installer: Add bootstrap installer for Windows (see #4093)
Add a shared CEF installer that downloads, verifies, and manages CEF
binary distributions on Windows. The installer is embedded in
application bootstrap binaries and resolves the correct CEF version
from a CDN manifest based on each application's version and ABI
compatibility requirements.

Key components:
- CDN manifest parsing and version resolution
- WinHTTP-based download with SHA-1/SHA-256 integrity verification
- Authenticode catalog (.cat) signature verification
- Parallel XZ decompression for fast archive extraction
- Per-version metadata (cef_version.json) with full version tracking
- Shared installation database for multi-app version management
- Version pruning to reclaim disk space from unused versions
- Revocation list support (compiled-in baseline + CDN delta)
- Progress UI with WM_COPYDATA-based cancellation
- Bundled CEF fallback for offline/CDN-failure scenarios
2026-07-27 14:04:48 -04:00

92 lines
3.6 KiB
Python

#!/usr/bin/env python3
# Copyright 2026 The Chromium Embedded Framework Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""E2E tests verifying installer exit codes.
Parametrized test covering reachable exit codes.
"""
import os
import unittest
from e2e_test_base import (E2ETestBase, EXIT_CONFIG_ERROR, EXIT_NETWORK_ERROR,
EXIT_NO_MATCHING_VERSION, EXIT_RELAUNCHED,
EXIT_SUCCESS, FLAG_BACKGROUND, FLAG_DOWNLOAD_PATH,
FLAG_HEADLESS, FLAG_UNINSTALL, FLAG_UPDATE)
class TestExitCodes(E2ETestBase):
def test_exit_code_success(self):
"""Exit code 0: Successful install."""
version, abi_hash = self.build_cdn()
self.embed_test_config(
appid='e2e00021-0000-0000-0000-000000000000',
vmin=version,
abi_hash=abi_hash,
)
exit_code, _, _ = self.run_installer([FLAG_UPDATE, FLAG_HEADLESS])
self.assertEqual(EXIT_SUCCESS, exit_code)
def test_exit_code_config_error(self):
"""Exit code 100: Invalid config."""
self.embed_raw_config_resource(self.bootstrap_exe, 'NOT VALID JSON {{{')
exit_code, _, _ = self.run_installer([FLAG_UPDATE, FLAG_HEADLESS],
use_local_cdn=False)
self.assertEqual(EXIT_CONFIG_ERROR, exit_code)
def test_exit_code_network_error(self):
"""Exit code >= 100: Empty CDN causes download/resolve failure."""
self.embed_test_config(
appid='e2e00021-0101-0101-0101-010101010101',
vmin=self.test_version,
abi_hash='a1b2c3d4e5f6',
)
empty_cdn = os.path.join(self.temp_dir, 'empty_cdn')
os.makedirs(empty_cdn)
exit_code, _, _ = self.run_installer(
[FLAG_UPDATE, FLAG_HEADLESS, f'{FLAG_DOWNLOAD_PATH}={empty_cdn}'],
use_local_cdn=False)
# Local download mode with missing manifest reports either
# kExitCodeNetworkError (101) or kExitCodeNoMatchingVersion (103)
# depending on whether the manifest is missing vs empty.
self.assertIn(exit_code, (EXIT_NETWORK_ERROR, EXIT_NO_MATCHING_VERSION))
def test_exit_code_no_matching_version(self):
"""Exit code 103: No CDN version satisfies the config range."""
abi_hash = 'a1b2c3d4e5f6'
self.build_cdn(version=self.test_version, abi_hash=abi_hash)
# vmin higher than what the CDN offers.
self.embed_test_config(
appid='e2e00021-0103-0103-0103-010301030103',
vmin=self.test_version_higher,
abi_hash=abi_hash,
)
exit_code, _, _ = self.run_installer([FLAG_UPDATE, FLAG_HEADLESS])
self.assertEqual(EXIT_NO_MATCHING_VERSION, exit_code)
def test_exit_code_relaunched(self):
"""Exit code 109: explicit background uninstall starts one child."""
version, abi_hash = self.build_cdn()
appid = 'e2e00021-0109-0109-0109-010901090109'
self.embed_test_config(
appid=appid,
vmin=version,
abi_hash=abi_hash,
)
# Install first.
exit_code, _, _ = self.run_installer([FLAG_UPDATE, FLAG_HEADLESS])
self.assertEqual(EXIT_SUCCESS, exit_code)
relaunch_dirs = self.snapshot_uninstall_relaunch_dirs()
env = {'PATH': self.build_dir + os.pathsep + os.environ.get('PATH', '')}
exit_code, _, stderr = self.run_installer(
[FLAG_UNINSTALL, FLAG_BACKGROUND, FLAG_HEADLESS], env=env)
self.assertEqual(EXIT_RELAUNCHED, exit_code,
stderr.decode(errors='replace'))
self.wait_for_relaunched_uninstall(appid,
relaunch_dirs,
os.path.basename(self.bootstrap_exe),
expected_index_versions=())