new unit tests, hehe 67
tests / linux (push) Failing after 2m18s
tests / windows (push) Skipped
tests / macos (push) Skipped
tests / package-smoke-linux (push) Skipped
tests / package-smoke-windows (push) Skipped
tests / package-smoke-macos (push) Skipped

Signed-off-by: galeon <dertiellis@gmail.com>
This commit is contained in:
galeon committed 2026-10-12 13:14:08 +03:00
1 parent ebf8ff7869
commit 41599fa82f
67 files changed
+8775 -4

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
# Дымовая проверка установленного дерева (результат cmake --install) на Windows.
#
# powershell -File tests\scripts\smoke_installed.ps1 -Prefix C:\r\bl-smoke-stage
#
# Проверяет, что windeployqt положил всё нужное (DLL Qt, плагины платформ и QML),
# лаунчер запускается без окна и через 10 секунд ещё жив, а в логе нет ошибок
# загрузки модулей.
#
# На Windows лаунчер берёт папку профиля у системы, а не из переменных окружения,
# поэтому работает в настоящей %APPDATA%\BiLauncher учётной записи раннера. Если
# её до запуска не было, скрипт убирает её за собой.
param(
[Parameter(Mandatory = $true)][string]$Prefix,
[int]$RunSeconds = 10
)
$ErrorActionPreference = "Stop"
function Fail($message) { Write-Host "SMOKE FAIL: $message"; exit 1 }
$bin = Join-Path $Prefix "bin\BiLauncher.exe"
if (-not (Test-Path $bin)) { Fail "нет $bin" }
foreach ($required in @("bin\Qt6Core.dll", "bin\Qt6Quick.dll", "bin\Qt6Network.dll",
"bin\platforms\qwindows.dll", "bin\qml\QtQuick\Controls")) {
if (-not (Test-Path (Join-Path $Prefix $required))) { Fail "нет $required" }
}
if (-not (Get-ChildItem (Join-Path $Prefix "bin\tls") -Filter "*.dll" -ErrorAction SilentlyContinue)) {
Fail "нет TLS-плагина (bin\tls) — лаунчер не сможет ходить по https"
}
$profileRoot = Join-Path $env:APPDATA "BiLauncher"
$existedBefore = Test-Path $profileRoot
$log = Join-Path $env:TEMP ("bilauncher-smoke-" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Force $log | Out-Null
$stdout = Join-Path $log "stdout.log"
$stderr = Join-Path $log "stderr.log"
$env:QT_QPA_PLATFORM = "offscreen"
$env:QT_FORCE_STDERR_LOGGING = "1"
$env:QTWEBENGINE_CHROMIUM_FLAGS = "--disable-gpu"
try {
$process = Start-Process -FilePath $bin -PassThru -NoNewWindow `
-RedirectStandardOutput $stdout -RedirectStandardError $stderr
Start-Sleep -Seconds $RunSeconds
$alive = -not $process.HasExited
if ($alive) { Stop-Process -Id $process.Id -Force; $process.WaitForExit(5000) | Out-Null }
$text = ""
if (Test-Path $stderr) { $text += Get-Content $stderr -Raw }
if (Test-Path $stdout) { $text += Get-Content $stdout -Raw }
Write-Host "----- лог запуска -----"
Write-Host $text
if (-not $alive) { Fail "лаунчер завершился раньше чем через $RunSeconds с (код $($process.ExitCode))" }
if ($text -match "is not installed|Cannot load library|could not find the Qt platform plugin|QQmlApplicationEngine failed") {
Fail "в логе ошибки загрузки модулей"
}
if (-not (Test-Path (Join-Path $profileRoot "settings.json"))) { Fail "лаунчер не создал $profileRoot\settings.json" }
Write-Host "SMOKE OK: $bin"
}
finally {
Remove-Item -Recurse -Force $log -ErrorAction SilentlyContinue
if (-not $existedBefore) { Remove-Item -Recurse -Force $profileRoot -ErrorAction SilentlyContinue }
}
+105
View File
@@ -0,0 +1,105 @@
#!/usr/bin/env bash
# Дымовая проверка установленного дерева (результат cmake --install) на Linux и macOS.
#
# tests/scripts/smoke_installed.sh <prefix>
#
# Linux: <prefix>/bin/BiLauncher (+ lib/BiLauncher/libz.so.1, плагины Qt рядом)
# macOS: <prefix>/BiLauncher.app
#
# Проверяет, что деплой Qt положил всё нужное: бинарник не ссылается на
# библиотеки вне дерева (ldd/otool), запускается без окна и через 10 секунд
# ещё жив, а в логе нет «module is not installed», «Cannot load library» и т. п.
# Запуск идёт с подменённым HOME — настоящие данные лаунчера на машине не трогаются.
set -euo pipefail
PREFIX="$(cd "${1:?нужен путь к установленному дереву}" && pwd)"
RUN_SECONDS="${RUN_SECONDS:-10}"
fail() { echo "SMOKE FAIL: $*" >&2; exit 1; }
case "$(uname -s)" in
Darwin)
APP="$PREFIX/BiLauncher.app"
BIN="$APP/Contents/MacOS/BiLauncher"
[ -x "$BIN" ] || fail "нет $BIN"
[ -f "$APP/Contents/Resources/icon.icns" ] || fail "нет иконки в бандле"
/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$APP/Contents/Info.plist" >/dev/null \
|| fail "в Info.plist нет версии"
# Ссылки на Qt должны вести внутрь бандла, а не в папку Qt сборочной машины.
if otool -L "$BIN" | tail -n +2 | grep -E '/Qt/|/Users/|/home/' ; then
fail "бинарник ссылается на библиотеки вне бандла"
fi
[ -d "$APP/Contents/Frameworks/QtQuick.framework" ] || fail "нет QtQuick.framework в бандле"
[ -d "$APP/Contents/PlugIns/platforms" ] || fail "нет плагинов платформ"
# Деплой идёт с -hardened-runtime: без подписи dyld откажется грузить фреймворки
# («different Team IDs»). Подписываем ad-hoc ровно как release.yml перед упаковкой.
codesign --force --deep --sign - "$APP" >/dev/null 2>&1 || fail "ad-hoc подпись не удалась"
codesign --verify --deep --strict "$APP" || fail "подпись бандла не проходит проверку"
;;
Linux)
BIN="$PREFIX/bin/BiLauncher"
[ -x "$BIN" ] || fail "нет $BIN"
[ -f "$PREFIX/lib/BiLauncher/libz.so.1" ] || fail "нет эталонного zlib (lib/BiLauncher/libz.so.1)"
[ -f "$PREFIX/share/applications/bilauncher.desktop" ] || fail "нет .desktop-файла"
[ -f "$PREFIX/share/icons/hicolor/256x256/apps/bilauncher.png" ] || fail "нет иконки hicolor"
[ -f "$PREFIX/share/doc/BiLauncher/LICENSE" ] || fail "нет LICENSE в share/doc"
# Все разделяемые библиотеки — бинарника, Qt и плагинов — должны находиться.
missing=0
while IFS= read -r -d '' file; do
if ldd "$file" 2>/dev/null | grep -q 'not found'; then
echo "не хватает библиотек для $file:" >&2
ldd "$file" | grep 'not found' >&2
missing=1
fi
done < <(find "$PREFIX" \( -name '*.so*' -o -path '*/bin/BiLauncher' \) -type f -print0)
[ "$missing" = 0 ] || fail "ldd: есть ненайденные зависимости"
;;
*) fail "неизвестная система $(uname -s)" ;;
esac
# Платформа Qt. Проверяем то, что реально задеплоено: macdeployqt кладёт только
# cocoa — на macOS окно на 10 секунд действительно откроется (раннеру нужна
# GUI-сессия). На Linux берём offscreen, если деплой его положил, иначе xcb
# под xvfb-run (пакет xvfb, см. ci/setup-runner-linux.sh).
LAUNCH=()
PLATFORM=""
if [ "$(uname -s)" = Linux ]; then
if find "$PREFIX" -name 'libqoffscreen.so' | grep -q .; then
PLATFORM=offscreen
elif command -v xvfb-run >/dev/null; then
LAUNCH=(xvfb-run -a)
elif [ -z "${DISPLAY:-}" ]; then
fail "нет ни плагина offscreen в деплое, ни xvfb-run, ни DISPLAY"
fi
fi
SANDBOX="$(mktemp -d)"
LOG="$SANDBOX/stderr.log"
trap 'rm -rf "$SANDBOX"' EXIT
env HOME="$SANDBOX" \
${PLATFORM:+QT_QPA_PLATFORM=$PLATFORM} \
QT_FORCE_STDERR_LOGGING=1 \
QTWEBENGINE_DISABLE_SANDBOX=1 \
QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox --disable-gpu" \
${LAUNCH[@]+"${LAUNCH[@]}"} "$BIN" >"$LOG" 2>&1 &
PID=$!
sleep "$RUN_SECONDS"
if ! kill -0 "$PID" 2>/dev/null; then
wait "$PID" || true
echo "----- лог -----" >&2; cat "$LOG" >&2
fail "лаунчер завершился раньше чем через ${RUN_SECONDS} с"
fi
kill "$PID" 2>/dev/null || true
wait "$PID" 2>/dev/null || true
echo "----- лог запуска -----"; cat "$LOG"
if grep -E 'is not installed|Cannot load library|could not find the Qt platform plugin|QQmlApplicationEngine failed|module ".*" plugin ".*" not found|Каталог переводов' "$LOG"; then
fail "в логе ошибки загрузки модулей"
fi
# Лаунчер создал свою папку в подменённом HOME, а не где-то ещё.
if [ "$(uname -s)" = Darwin ]; then ROOT="$SANDBOX/Library/Application Support/BiLauncher"; else ROOT="$SANDBOX/BiLauncher"; fi
[ -f "$ROOT/settings.json" ] || fail "лаунчер не создал $ROOT/settings.json"
echo "SMOKE OK: $BIN"
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""Статические проверки без запуска лаунчера. Ненулевой код возврата при ошибке.
Запуск: python3 tests/scripts/static_checks.py <папка сборки с BILAUNCHER_BUILD_TESTS=ON>
1. tools/check_translations.py — каталог переводов цел и совпадает с кодом.
2. qmllint по модулю BiLauncher (цель BiLauncher_qmllint, её создаёт qt_add_qml_module).
В коде уже есть предупреждения, а код ради тестов не правится, поэтому
проверка работает «храповиком»: падает, только если предупреждений стало
больше, чем записано в tests/qmllint-baseline.txt. Стало меньше — просит
опустить планку, чтобы достигнутое не откатилось.
3. CHANGELOG.md содержит раздел для версии из project(BiLauncher VERSION …):
без него release.yml создаст релиз с пустым описанием (только предупреждение).
"""
import os, re, subprocess, sys
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
BASELINE = os.path.join(ROOT, "tests", "qmllint-baseline.txt")
def step(title):
print(f"\n=== {title}", flush=True)
def check_translations():
step("Каталог переводов")
return subprocess.call([sys.executable, os.path.join(ROOT, "tools", "check_translations.py")]) == 0
def check_qmllint(build_dir):
step("qmllint (BiLauncher_qmllint)")
cmake = os.environ.get("CMAKE", "cmake")
proc = subprocess.run([cmake, "--build", build_dir, "--target", "BiLauncher_qmllint"],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True,
encoding="utf-8", errors="replace")
output = proc.stdout
with open(os.path.join(build_dir, "qmllint.log"), "w", encoding="utf-8") as log:
log.write(output)
warnings = [line for line in output.splitlines() if line.startswith("Warning:")]
errors = [line for line in output.splitlines() if line.startswith("Error:")]
for line in warnings + errors:
print(line)
baseline = int(open(BASELINE, encoding="utf-8").read().split()[0])
print(f"\nпредупреждений: {len(warnings)}, ошибок: {len(errors)}, планка: {baseline}"
f" (полный вывод — {os.path.join(build_dir, 'qmllint.log')})")
if proc.returncode != 0 and not warnings and not errors:
print("qmllint не запустился — см. лог")
return False
if errors:
print("ОШИБКА: qmllint нашёл ошибки")
return False
if len(warnings) > baseline:
print(f"ОШИБКА: предупреждений стало больше ({len(warnings)} > {baseline}). "
"Исправьте новые или, если они осознанные, поднимите tests/qmllint-baseline.txt.")
return False
if len(warnings) < baseline:
print(f"Хорошо: предупреждений меньше планки — опустите tests/qmllint-baseline.txt до {len(warnings)}.")
return True
def check_changelog():
step("CHANGELOG.md и версия проекта")
cmake_text = open(os.path.join(ROOT, "CMakeLists.txt"), encoding="utf-8").read()
match = re.search(r"^project\(BiLauncher VERSION ([0-9]+\.[0-9]+\.[0-9]+)", cmake_text, re.M)
if not match:
print("ОШИБКА: не найден project(BiLauncher VERSION x.y.z)")
return False
version = match.group(1)
changelog = open(os.path.join(ROOT, "CHANGELOG.md"), encoding="utf-8").read()
if re.search(r"^## \[" + re.escape(version) + r"\]", changelog, re.M):
print(f"версия {version}: раздел в CHANGELOG.md есть")
else:
print(f"ПРЕДУПРЕЖДЕНИЕ: в CHANGELOG.md нет раздела ## [{version}] — описание релиза будет пустым")
return True
def main():
if len(sys.argv) != 2:
print(__doc__)
return 2
build_dir = os.path.abspath(sys.argv[1])
results = [check_translations(), check_qmllint(build_dir), check_changelog()]
print("\nИТОГ:", "OK" if all(results) else "ЕСТЬ ОШИБКИ")
return 0 if all(results) else 1
if __name__ == "__main__":
sys.exit(main())