From fe5cc4461cc9354582e63974a60fd96b66e1da15 Mon Sep 17 00:00:00 2001 From: Alexey Martemyanov Date: Sat, 17 Oct 2026 17:39:42 +0600 Subject: [PATCH] [2026-10-17] legacy-xctest-runner: macOS 12 arm64 + per-test run; virfield: UI test practice notes --- personal/projects/virfield.md | 20 ++++++++- personal/tech/legacy-xctest-runner.md | 61 ++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/personal/projects/virfield.md b/personal/projects/virfield.md index 8fdbf0b8..00f88036 100755 --- a/personal/projects/virfield.md +++ b/personal/projects/virfield.md @@ -1,6 +1,6 @@ # Virfield -Проверено: **2026-10-16**. Последний опубликованный stable Latest и установленная версия — [v2.1.1](https://github.com/mallexxx/virfield/releases/tag/v2.1.1), source `2c64888abed617722e79d618dd4911efa0c4b126`. Релиз опубликован после явного подтверждения владельца. Архив macOS ARM64 и SHA256SUMS скачаны с публичных URLs без авторизации; содержимое побайтно совпадает с проверенным установленным пакетом. Предыдущая публикация: [[personal/projects/virfield-release-v2.1.0]]. +Проверено: **2026-10-16** (практика UI-тестов — 2026-10-17, см. раздел ниже). Последний опубликованный stable Latest и установленная версия — [v2.1.1](https://github.com/mallexxx/virfield/releases/tag/v2.1.1), source `2c64888abed617722e79d618dd4911efa0c4b126`. Релиз опубликован после явного подтверждения владельца. Архив macOS ARM64 и SHA256SUMS скачаны с публичных URLs без авторизации; содержимое побайтно совпадает с проверенным установленным пакетом. Предыдущая публикация: [[personal/projects/virfield-release-v2.1.0]]. Текущий local/GitHub `main`: **`2c64888abed617722e79d618dd4911efa0c4b126`**, checkout чистый, локально и на origin только `main`. Изменение исправляет обработку ошибки `launchctl bootstrap` уже зарегистрированного собственного guest Keychain agent: recovery разрешён только после проверки точного launchd job, затем остаются все прежние native readiness gates. Добавлены закрытый bootstrap diagnostic и regression с настоящим shell-блоком; контрфактический тест на старом коде воспроизвёл отказ. Make check/race, Staticcheck, module verify, Govulncheck и make check из распакованного точного кандидата прошли. @@ -44,6 +44,24 @@ macOS make check/build/Staticcheck прошли; настоящий read-only vo Архив: `/private/tmp/virfield-release-clean-package-final/virfield-v0.0.0-release-cleanup-darwin-arm64.tar.gz`, SHA-256 `5522529bfd16246e7ba034dd6055c9d6ef89b00b5f290ff3ff9f64be6a32a204`. Это локальный проверенный пакет; отдельный GitHub Release/tag не создавался. [[personal/projects/virfield-release-cleanup-2026-10-16|Итоговый протокол релизной очистки]]. +## Практика: UI-тесты DDG на двух VM (2026-10-17) + +Использовали MCP клиент Claude Code, шаблоны `macos27` (macOS 27.0, Xcode 27.0, golden `uitest-27-v1`) и `monterey-xcode-13.4.1` (macOS 12.7.6, Xcode 13.4.1, `developer-v1`). Сборка и подпись на хосте, исполнение по pinned SSH. Подробности про macOS 12 — [[personal/tech/legacy-xctest-runner]]. + +Вопросы и проблемы: + +- **CLI `virfield` на машине клиента нет** (`~/Library/Application Support/Virfield/bin` отсутствует), поэтому `keygen`/`ssh-config` из руководства не выполнить. Ключ создан `ssh-keygen -t ed25519`, pinned `config` и `known_hosts` написаны вручную из `vm_lease`: `ssh.host_key`, `ip`, user `admin`; `StrictHostKeyChecking yes`. Работает, потому что IP Tart VM (192.168.64.x) доступен с хоста напрямую. Удобно, если бы MCP/доки описывали этот путь без CLI. +- **`ssh_key_in_use`**: один публичный ключ на один активный lease. Для второй VM нужен второй ключ. +- **`resource_exhausted` по диску**: хранилище `samsung-tart` ≈214 ГБ, macOS 27 резервирует 140 ГБ, Monterey 120 ГБ, safety reserve 20 ГБ → вместе не помещаются (headroom −87 ГБ). Пришлось сначала освободить macOS 27 (с разрешения владельца) и только потом брать Monterey. Шаблон на другом хранилище (`release-check`) есть, но выбирать его самостоятельно клиент не стал. +- **`virfield_status` ≈112 тыс. символов** — превышает лимит ответа, сохраняется в файл. Разбирать `jq`: `.capacity`, `.leases`, `.template_availability`. В `.templates[]` нет полей `xcode`/`macos` версии; версии и `installed_images` смотреть в `image_catalog` (`inventory.configured_images`). +- Тайминги: prepare до `ready` ≈40 с для обеих VM; release → `released` ≈7 с (job сначала `delete_dispatched`, итоговое состояние читать из `vm_lease`, не ждать только `virfield_job`). +- **Запись экрана**: на `uitest-27-v1` `screencapture -v` работает по обычному SSH; на macOS 12 (`developer-v1`) `capture error`, нет Screen Recording TCC, SIP включён. Если нужна запись на старых VM, нужен golden с заранее выданным разрешением. +- **UI automation**: macOS 12 VM — Developer Mode уже включён, sudo без пароля, но `automationmodetool enable-automationmode-without-authentication` нужно выполнить; `ui_testing` проба помогла бы здесь. Для запуска из SSH нужна консольная GUI-сессия (Terminal `.command`). +- Remote shell zsh: нет `timeout`, `$var` не разбивается на слова — при автоматизации писать скрипты файлами. +- Запуск из `xcodebuild test-without-building -xctestrun` по скопированным `Products` (macOS 27) работает; `Scheme`-pre-actions (`clean-app.sh`, `tests-server`) при этом **не** выполняются. +- Повторы `vm_acquire` — с новым idempotency key, если меняется ключ SSH/шаблон; тот же ключ и body только для настоящего retry. +- Клиентская сторона (не virfield): auto-mode classifier заблокировал `vm_acquire` для шаблона, который пользователь не называл; разрешение нужно давать явно. + ## Ограничения и дальнейший план Следующие задачи не входят в принятую установленную VM/MCP/Broker-приёмку и не объявляются реализованными: diff --git a/personal/tech/legacy-xctest-runner.md b/personal/tech/legacy-xctest-runner.md index 543bf1ad..cca9c00b 100755 --- a/personal/tech/legacy-xctest-runner.md +++ b/personal/tech/legacy-xctest-runner.md @@ -1,7 +1,7 @@ --- title: Legacy XCTest runner (run new-Xcode UI tests on macOS 12) namespace: personal -updated: '2026-10-14' +updated: '2026-10-17' tags: - xctest - ui-tests @@ -12,9 +12,13 @@ tags: # Legacy XCTest runner Runs DDG macOS UI tests built with the current Xcode (27.x) on a Mac that can only -run an old Xcode, e.g. the MBP 2014 node (Monterey 12.6.8, Intel, Xcode 13.4.1). +run an old Xcode, e.g. macOS 12 + Xcode 13.4.1. Работает на двух типах целей: + +- MBP 2014 node (Monterey 12.6.8, **Intel x86_64**), 2026-10-12; +- Tart VM из virfield, шаблон `monterey-xcode-13.4.1` (macOS 12.7.6, **arm64**, Xcode 13.4.1 в `/Applications/Xcode.app`), 2026-10-17. Location: `~/Developer/legacy-xctest-runner/` (not committed anywhere). +macOS 12 **не входит в CI matrix** (PR: только macOS 27; полный прогон: 14, 15, 27), это чисто локальная проверка. Минимум приложения — macOS 12.3. ## Why it is needed @@ -23,22 +27,26 @@ Location: `~/Developer/legacy-xctest-runner/` (not committed anywhere). if hosted by the old Xcode's runner. - The bundle imports 2 Swift symbols missing from Xcode 13 XCTest: `XCUIElement.typeKey(_:modifierFlags:)` (mangled under `XCUIAutomation`) and - `XCTIssue.init(…severity:)`. `XCTestCompat.swift` forwards them. + `XCTIssue.init(…severity:)`. `XCTestCompat.swift` forwards them + (так что `typeKey(XCUIKeyboardKey, …)` в тестах работает). ## How it works - `package.sh ` — collects `DuckDuckGo Review.app`, - `tests-server`, `UI Tests.xctest` + runner files. + `tests-server`, `UI Tests.xctest` + runner files. Ждёт `Build/Products/Review` с + `DuckDuckGo Review.app`, `tests-server`, `UI Tests-Runner.app`. - `run.sh [--gui] [result-name]` on the target Mac: - builds `XCTestCompat.framework` (re-exports old XCTest + libXCTestSwiftSupport, adds forwarders); - hosts the bundle in Xcode 13's `XCTRunner.app`, `install_name_tool` repoints the bundle's XCTest/libXCTestSwiftSupport imports at XCTestCompat; + - **режет runner до нативного слайса** (`lipo -thin`, см. ниже), добавлено 2026-10-17; - repeats `macOS UI Tests CI` scheme pre-actions (clean-app review, suppress Move-to-Applications, start tests-server); - `xcodebuild test-without-building` with `UITests.xctestrun` (FormatVersion 1), then kills tests-server and the app (old XCTest doesn't terminate it). - `--gui`: over SSH xcodebuild can't reach the runner; relaunches itself via a Terminal `.command` in the console session, waits, closes finished windows. +- Env `SKIP_BUILD=1` (патч на VM, в локальный `run.sh` не внесён): пропустить `build_compat` и `assemble_runner`, если уже собраны. Нужен для запуска по одному тесту. Build on the host (spell flags out — zsh doesn't word-split `$var`): @@ -47,6 +55,8 @@ xcodebuild build-for-testing -workspace DuckDuckGo.xcworkspace -scheme "macOS UI xcodebuild build -workspace DuckDuckGo.xcworkspace -scheme "macOS Browser" -configuration Review -destination "platform=macOS,arch=x86_64" -derivedDataPath
ONLY_ACTIVE_ARCH=YES -skipPackagePluginValidation -skipMacroValidation ``` +Для Apple Silicon VM архитектура `arm64`. Подписанное на хосте приложение 2026-10-17 собирали так: `xcodebuild archive -scheme "macOS Browser Review" -configuration Review … EXCLUDED_ARCHS=x86_64 RELEASE_PRODUCT_NAME_OVERRIDE=DuckDuckGo` + `-exportArchive` с **копией** `macOS/scripts/assets/ExportOptions.plist` (Developer ID, `signingCertificate` = SHA-1 из keychain; tracked plist не править, как делает `archive.sh`). Нотаризация внутри VM не нужна. Профили `match Direct …review` уже лежат в `~/Library/Developer/Xcode/UserData/Provisioning Profiles`. + ## Target Mac prerequisites (once per boot volume, needs sudo) ```bash @@ -58,19 +68,48 @@ Without them testmanagerd shows an admin-password prompt on the display ("Timed out while enabling automation mode"). Virfield's node probe now reports `ui_testing` (`ready` / `devtools_disabled` / `automation_mode_requires_auth` / `no_console_session`); setup script `/Users/admin/Developer/virfield/deploy/node-ui-testing.sh`. +В Tart VM `monterey-xcode-13.4.1` Developer Mode уже включён, sudo без пароля; `automationmodetool` выполнить надо. ## Gotchas found +**Запуск** + +- **arm64e: SIGKILL 137 на старте раннера (Apple Silicon).** `XCTRunner.app` из Xcode 13.4.1 — universal `x86_64 arm64 arm64e`, ядро выбирает arm64e: `exec_mach_imgact: not running binary "UI Tests-Runner" built against preview arm64e ABI`; xcodebuild: «Launched process exited during launch» / `Failed to install or launch the test runner`. Лечится `lipo -thin $(uname -m)` в `assemble_runner` (уже в `run.sh`). На Intel не проявлялось. +- `--gui` запускает себя из `.command` по **`$0`**; из SSH вызывать `run.sh` только по **абсолютному пути**, иначе `./run.sh: No such file or directory` в Terminal (cwd=home). +- `LEGACY_XCODE` из окружения SSH **не доходит** до Terminal `.command`: `xcrun: error: missing DEVELOPER_DIR path: /Applications/Xcode13.4.1.app`. Либо `sudo ln -sfn /Applications/Xcode.app /Applications/Xcode13.4.1.app`, либо править дефолт. +- Over SSH xcodebuild без `--gui` не достаёт раннер; remote shell — zsh: нет `timeout` (используй `perl -e 'alarm N; exec @ARGV'`), `$var` не делится на слова, `log` — builtin (`/usr/bin/log show`). +- Exit code `.command`-обёртки (`exit=0` в логах) **не равен** результату тестов. Смотреть `Executed N tests, with M failures` и `Test Case … passed|failed`. `Executed 0 tests, with 1 failure` = упал class `setUp`. +- Старый xcodebuild пишет `LLVM Profile Error: Failed to write file default.profraw: Read-only file system` — безвредно. +- Приложение: LSMinimumSystemVersion 12.3. arm64 VM требует arm64-сборку (Review app после `EXCLUDED_ARCHS=x86_64`, test bundle arm64). + +**Тесты** + +- **Старый XCTest не завершает приложение между тестами.** При запуске класса целиком каждый следующий тест стартует поверх предыдущего: `Failed to synthesize event: Unable to synthesize gesture request N 'click' because gesture request M 'Type 'n' key with modifiers ⌘' is still in progress`, `Timed out while evaluating UI query`, лавина падений без реальных assert (первый прогон: 49 «failures» на 25 тестах Duck.ai, 42 на 24 тестах поискового класса). Тот же тест по одному проходит за ~5 с. **Решение: один `xcodebuild` на каждый тест** со свежим `prepare_environment` (чистые defaults, перезапуск tests-server и приложения), `SKIP_BUILD=1` после первого. 88 тестов ≈ 25–30 мин. Цикл `each.sh` читает `tests-list.txt` (`Class/method`), пишет `summary-each.txt`, запускается из Terminal `.command`. +- **`UITests.setAutocompleteToggleBeforeTestcaseRuns(false)` на macOS 12 падает по таймауту** (`Failed to get matching snapshots: Timed out while evaluating UI query`, окно Settings) → тесты класса не стартуют (`Executed 0 tests, with 1 failure`, ~190 с). Затронуты все классы с этим `setUp`, включая `AddressBarKeyboardShortcutsTests`. Локальный обход без коммита: убрать вызов хелпера при сборке бандла и в `prepare_environment` писать `defaults write com.duckduckgo.macos.browser.review preferences.appearance.show-autocomplete-suggestions -bool false`. +- Редкий флейк: `Failed to compute hit point for (null)` → раннер падает при снятии скриншота (`Restarting after unexpected exit, crash, or test timeout`, итог `noresult`). Перезапуск одного теста помогает. - Repo `Logger` (`macOS/UITests/Common/UITests.swift`) calls private `-[XCTContext _recordActivityMessageWithFormat:]`; old XCTest lacks it → guard - with `responds(to:)` (done on branch `alex/fix-save-credentials-tooltip-crash-macos12`). -- Remote shell is zsh: `log` is a builtin — use `/usr/bin/log show`. -- MBP has a different SSH host key per boot volume; use the Virfield lease's - generated `ssh-config` (pins the booted volume's key). + with `responds(to:)` (в main уже есть). - Hover tracking in the app uses `.activeInKeyWindow`; popovers that open without focus don't get hover events. +- Текст Duck.ai omnibar (`AIChatOmnibarTextContainerViewController.textView`) **не виден в accessibility-дереве** (контейнер `…view` — одиночный `Other`), в том числе на macOS 27. Ключи шлются через `app.typeKey`, текст читается через Cmd+A, Cmd+C и `NSPasteboard`. + +**Окружение / запись** + +- `screencapture -v` на macOS 12 VM: `capture error The operation could not be completed` и по SSH, и из Terminal в GUI-сессии (нет Screen Recording TCC, SIP включён, выдать нельзя). На macOS 27 golden `uitest-27-v1` работает по обычному SSH. Для macOS 12 записи экрана нет — только логи и `.xcresult`. +- MBP has a different SSH host key per boot volume; use the Virfield lease's + generated `ssh-config` (pins the booted volume's key). Для Tart VM IP (192.168.64.x) доступен напрямую с хоста. +- Диск Tart: `samsung-tart` ≈214 ГБ, macOS 27 clone резервирует 140 ГБ, Monterey 120 ГБ — вместе не помещаются, см. [[virfield]]. + +## Находки на macOS 12 (PR 4548, address bar word selection) + +2026-10-17, ветка `alex/bug-08b-addressbar-selection`: тесты Opt+Shift+←/→, Cmd+Shift+←/→, Shift+←/→, Cmd+A, delete/forward-delete в адресной строке (URL, поисковый запрос, суффикс) и Duck.ai. + +- На macOS 12 после **Cmd+Shift+←** `selectionAffinity` остаётся прежним (на 27 становится `.upstream`) → Opt+Shift+→ не сжимала выделение слева. Исправлено явной установкой affinity в `AddressBarTextEditor` (`moveToBeginningOfLine/LeftEndOfLine/EndOfLine/RightEndOfLine…AndModifySelection`). Тот же класс проблемы — `selectAll`: affinity теперь явно `.downstream`. + +## Результаты запусков + +- 2026-10-12, MBP 2014 (Intel): воспроизведён Sentry crash `NSInternalInconsistencyException SaveCredentialsViewController.loadView` (`isfinite(newOrigin.x)` on macOS 12) до фикса. +- 2026-10-17, Tart VM macOS 12.7.6 arm64: по-тестовый прогон 88 новых тестов. Первый проход 85 passed / 2 failed (находка про Cmd+Shift+← affinity) / 1 noresult (флейк скриншота). После фикса три теста перепроверены — passed. -First used: 2026-10-12, reproducing Sentry crash -`NSInternalInconsistencyException SaveCredentialsViewController.loadView` -(`isfinite(newOrigin.x)` on macOS 12) — reproduced before fix on the MBP. See also [[virfield]].