Проверка на портале

Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, левое меню, раскладка компонентов, агенты, таблица импорта, поведение при обновлении. Проверять это приходится руками — и лучше по списку, потому что забытый шаг находит не разработчик, а клиент.

Всё, что ниже рантайма Битрикса, тестами не закрыть: установка, права, левое меню, раскладка компонентов, агенты, таблица импорта, поведение при обновлении. Проверять это приходится руками — и лучше по списку, потому что забытый шаг находит не разработчик, а клиент.

Процедура рассчитана на отдельный стенд, а не на боевой портал. Шаги «удалить модуль» и «поставить на CP1251» на рабочем портале делать нельзя: удаление стирает таблицу импорта.

Раскладка репозитория — в module-structure.md, сборка — в build-and-install.md.

Что понадобится

портал«коробка» Битрикс24 (для левого меню нужен intranet) или БУС, главный модуль 22.600.300 и выше
PHP8.2 и выше, расширения mbstring и xmlreader
кодировкатолько UTF-8
shef.options3.0.0 и выше, установлен
shef.problems2.0.0 и выше, установлен
доступадминистратор портала, второй пользователь без прав администратора, доступ к файлам по ssh
архивсо страницы релиза либо собранный ./build.sh
модуль-импортлюбой модуль с наследником Sync\FromFile\AFileProcess и страницей shef.insync:import.from.file в левом меню — например, shef.demosync

Для сценария «обновление» нужен стенд, где уже стоит 1.2.x — на нём проверяется то, ради чего 2.0.0 сделана мажорной.

Перед началом

Снимите копию каталога модуля, настроек, таблицы импорта и компонентов 1.x в /local — шаги с удалением необратимы, а установщик удаляет /local/components/shef.insync без проверки содержимого (в 1.x там мог править проект):

cp -a /var/www/portal/bitrix/modules/shef.insync /tmp/shef.insync.before 2>/dev/null
cp -a /var/www/portal/local/components/shef.insync /tmp/local-components.before 2>/dev/null
mysqldump -u… portal b_option --where="MODULE_ID='shef.insync'" > /tmp/opt.before.sql
mysqldump -u… portal shef_insync_model > /tmp/model.before.sql
ls /var/www/portal/local/components/ /var/www/portal/bitrix/components/ /var/www/portal/bitrix/js/ | sort > /tmp/public.before

0. Архив — тот самый

Архив собирается побайтово одинаково у всех, кто взял тот же коммит:

git clone https://github.com/bx-shef/insync.git
cd insync && git checkout <тег проверяемой версии>
./build.sh                       # последняя строка напечатает sha256
sha256sum /путь/к/скачанному/shef.insync.zip

Хеши обязаны совпасть. Первым уровнем внутри архива — ровно shef.insync/:

unzip -Z1 shef.insync.zip | cut -d/ -f1 | sort -u

A. Чистая установка

  1. Убедиться, что shef.options 3.0.0+ и shef.problems 2.0.0+ стоят.
  2. Распаковать в bitrix/modules/, чтобы получилось bitrix/modules/shef.insync/.
  3. Marketplace → Установленные решения → «SH InSync» → установить.

Ожидается: «Модуль успешно установлен»; появились /bitrix/components/shef.insync/ (два компонента) и /bitrix/js/shef-insync/ui-anchors/; в /local/components/ каталога shef.insync нет; в БД появилась таблица shef_insync_model; в левом меню появился раздел «SH Импорт» со страницами «Статистика» и «Записи импорта».

Отдельно: на стенде без shef.options 3.x или без shef.problems 2.x установка обязана отказать с текстом про модуль и версию — а не поставиться и упасть на первой странице.

B. Обновление с 1.2.x — главный сценарий 2.0.0

Делается на стенде, где стоит 1.2.x, есть строки в таблице импорта и хотя бы один агент импорта.

  1. Запомнить, что было:
ls /var/www/portal/local/components/shef.insync/      # в 1.x есть
mysql -e "SELECT COUNT(*) FROM shef_insync_model" portal
  1. Выключить агенты импорта (/bitrix/admin/agent_list.php, модули импорта) и дождаться, пока текущий запуск закончится. Модели 2.0.0 знают колонку ID, которой в таблице 1.x нет: между заменой файлов и SyncTable::init() каждый запрос агента к таблице упадёт.
  2. Обновить shef.options до 3.x и shef.problems до 2.x.
  3. Заменить файлы модуля содержимым архива 2.0.0. Замена файлов не запускает установщик: компоненты 1.x в /local/components/shef.insync останутся и перекроют новые. Разложите файлы установщиком, не удаляя модуль (удаление стёрло бы таблицу импорта) — в «Командной PHP-строке» администратора:
require $_SERVER['DOCUMENT_ROOT'].'/bitrix/modules/shef.insync/install/index.php';
(new shef_insync())->InstallFiles();
\Bitrix\Main\Loader::includeModule('shef.insync');
\Shef\InSync\Sync\Model\SyncTable::init();   // ключ таблицы 1.x -> 2.x

До перевода проверьте, что внешние коды не совпадают в первых 191 символе — иначе уникальный индекс не встанет и init() откажет (строки не тронет):

SELECT ORIGINATOR_ID, LEFT(ORIGIN_ID, 191) AS K, COUNT(*) FROM shef_insync_model
GROUP BY ORIGINATOR_ID, K HAVING COUNT(*) > 1;

Пусто — переводите. Нет — лишние строки (обычно давно упавшие) удалить или разобрать до перевода.

init() переводит таблицу импорта 1.x на ключ 2.x: первичный ключ — новая колонка ID, внешний код уникален в пределах кода импорта, индексы 1.x (_origs, _orig_id, _originator_id) снимаются. Строки остаются; повторный вызов ничего не делает. Перевод — один ALTER TABLE, MySQL перестраивает таблицу и на это время не пускает запись: большую таблицу (SELECT COUNT(*) из п. 1) переводите в окно без импорта. Ключ таблицы не 1.x и не 2.x — init() отказывает и ничего не меняет.

  1. Включить агенты импорта обратно.

Ожидается:

  • /local/components/shef.insync/ удалён, /bitrix/components/shef.insync/ на месте;
  • число строк в shef_insync_model то же;
  • SHOW KEYS FROM shef_insync_model — ровно два ключа: PRIMARY на ID и уникальный shef_insync_model_origin на ORIGINATOR_ID, ORIGIN_ID; индексы, которые проект завёл на таблице сам, — на месте;
  • страница «Статистика» открывается администратору, грид и список агентов на месте, кнопки агентов работают (см. D);
  • страница настроек модуля открывается (см. C) — в 1.x она падала бы на shef.options 3.x с «Unknown named parameter»;
  • в журнале PHP нет Undefined array key, Class "Shef\UiClear\..." not found, Call to undefined function _showError().
  1. Перенести каталог импорта за корень сайта и перенастроить обмены — по security.md, «После обновления с 1.x».

Ожидается: файлы из /upload/import/ лежат в <каталог импорта>/, /upload/import удалён, обмен кладёт новый файл в <каталог импорта>/<код>/, агент его забирает.

C. Страница настроек

Настройки → Настройки модулей → SH InSync.

Ожидается: вкладка «Общие», в ней «Сколько дней хранится файл в результате импорта» со значениями 1, 2, 3, 5, 15, 30; по умолчанию — 3. Сохранить 15 — значение сохранилось.

Если модуль-импорт выводит на своей странице настроек опции Options\Agent\Option или Options\Import\FromFile\Option: у администратора кнопки запуска/остановки агента и импорта работают; у пользователя с правом «Чтение» на тот модуль кнопки агента не видны.

D. Права на страницах и в ajax

Под пользователем без прав (не администратор, прав на модули нет):

  1. Раздел «SH Импорт» в левом меню — страниц модуля не видно; прямой адрес /page/shinsync/statimportlocal/ — «Недостаточно прав».
  2. Прямой вызов действия из консоли браузера на любой странице портала:
BX.ajax.runComponentAction('shef.insync:import.stat.local', 'stopAgent', {mode: 'class', data: {id: 1}})

Ожидается: ошибка, агент с ID 1 (агент ядра) не выключен — проверить на /bitrix/admin/agent_list.php.

  1. То же для контроллера страницы настроек: скопировать под администратором адрес кнопки агента (/bitrix/services/main/ajax.php?action=…stopAgent&…), открыть его под пользователем без прав, подставив agentId=1&moduleId=main и его sessid (BX.bitrix_sessid()) — ошибка, агент не тронут.
  2. Пользователю дать «Запись» на sale (или другой модуль ядра со своими агентами), повторить п. 3 с ID агента sale и moduleId=sale — ошибка «Agent not found», агент не тронут: модуль трогает только агенты импорта.

Под администратором: страница статистики открывается, агент модуля-импорта выключается и включается кнопкой, «Очистить» у строки грида удаляет только строки этой загрузки.

E. Импорт файла

На странице импорта из файла модуля-импорта (левое меню «SH Импорт»):

  1. «Скачать пример» — скачивается файл-пример.
  2. Загрузить этот пример — «Загрузка произведена», статистика по строкам.
  3. Загрузить файл test.php (переименуйте любой текстовый) — отказ «Wrong file type», в <каталог импорта>/<код>/ файла нет.
  4. Файл, в строках которого есть <b>жирный</b> и ошибка разбора, — в блоке ошибок текст виден как текст, а не жирным.

Ожидается: каталог импорта — вне корня сайта (/home/bitrix/sh_import на BitrixVM, если не задан свой); в <каталог импорта>/copy/<код>/ архив с именем done_<код>_<дата>_<16 символов>.<расш> — хвост случайный.

F. Откуда взяты библиотеки XML

\Bitrix\Main\Loader::includeModule('shef.insync');
echo (new ReflectionClass(\SbWereWolf\XmlNavigator\Extraction\HierarchyComposer::class))->getFileName();

Ожидается: проект без Composer — путь в …/shef.insync/vendor/sbwerewolf/…; проект с Composer, где стоит sbwerewolf/xml-navigator, — путь в vendor проекта. Во втором случае версия там обязана быть 7.2.x: ветки 8+ требуют PHP 8.4 и разбирают XML в тот же формат, но модуль на них не проверялся.

G. Агент импорта

Агент модуля-импорта (наследник Sync\FromFile\AAgent) после загрузки файла:

Ожидается: строки из shef_insync_model уходят пачками, успешные удаляются, ошибочные остаются со статусом F и сообщением; в журнале событий проблемы с типом SH_PROBLEMS_SYNC; страница статистики обновляется сама (pull), без ошибок в консоли браузера.

G2. Драйверы каталога

Из PHP-консоли на товаре торгового каталога (ID и тип цены — свои):

\Bitrix\Main\Loader::includeModule('shef.insync');
$price = new \Shef\InSync\Sync\Model\Catalog\Driver\Price();
var_dump($price->save(['PRODUCT_ID' => 1, 'CATALOG_GROUP_ID' => 1], ['PRICE' => 10, 'CURRENCY' => 'BYN'])->isSuccess());
var_dump($price->save(['PRODUCT_ID' => 1, 'CATALOG_GROUP_ID' => 1], ['PRICE' => 12.5, 'CURRENCY' => 'BYN'])->isSuccess());
var_dump((new \Shef\InSync\Sync\Model\Catalog\Driver\Product())->save(['ID' => 1], ['WEIGHT' => 250])->isSuccess());
var_dump((new \Shef\InSync\Sync\Model\Catalog\Driver\Amount())->save(['PRODUCT_ID' => 1], ['STORE_ID' => 1, 'AMOUNT' => 7])->isSuccess());

Ожидается: четыре true, ни одного Warning; у товара одна цена этого типа — 12.50, PRICE_SCALE заполнен; вес 250; остаток на складе 1 — 7 (при включённом складском учёте ядро остаток так не примет — это верно).

H. Удаление

  1. Marketplace → Установленные решения → «SH InSync» → удалить.

Ожидается:

  • /bitrix/components/shef.insync/, /bitrix/js/shef-insync/ и /local/components/shef.insync/ (если был) удалены, чужие компоненты на месте;
  • таблицы shef_insync_model нет, настроек модуля в b_option нет, настройки shef.options — на месте;
  • раздел «SH Импорт» из левого меню ушёл;
  • файлы в каталоге импорта остались: это данные проекта.

Формы «сохранить данные?» у модуля нет: удаление из админки стирает таблицу импорта всегда. Оставить данные — только из PHP-консоли: (new shef_insync())->UnInstallDB(['savedata' => 'Y']) после подключения /bitrix/modules/shef.insync/install/index.php.

Если модуль зависит от других (shef.* с shef.insync в requireModules), удаление обязано отказать и назвать их.

I. Портал в CP1251

Установка обязана отказать с текстом про UTF-8. На современных ядрах ветка недостижима — Application::isUtfMode() возвращает true без условий, — тогда в бланке отмечается «пропущено», и это верный ответ.

J. Примеры на живом ядре

for e in agent xml; do DOCUMENT_ROOT=/var/www/portal php examples/$e.php || echo "FAIL $e"; done

Ожидается: два раза ГОТОВО: …, ни одного FAIL, Warning, Deprecated.

Бланк результата

Версия: ____  Коммит: ____  sha256 архива сошёлся: да / нет
Ядро main: ____  PHP: ____  shef.options: ____  shef.problems: ____
Composer в проекте: да / нет   intranet: да / нет

0. Архив .................................. ок / не ок
A. Чистая установка ....................... ок / не ок
   без shef.options 3 / shef.problems 2 — отказ .. ок / не ок
B. Обновление с 1.2.x ..................... ок / не ок / нет стенда
C. Страница настроек ...................... ок / не ок
D. Права: без прав — отказ ................ ок / не ок
   агент ядра не тронут ................... ок / не ок
   «W» на sale — агенты sale не тронуты ... ок / не ок
E. Импорт файла ........................... ок / не ок
   .php отклонён .......................... ок / не ок
F. Библиотеки XML взяты из ................ модуль / Composer
G. Агент импорта .......................... ок / не ок
G2. Драйверы каталога ..................... ок / не ок
H. Удаление ............................... ок / не ок
I. CP1251 ................................. ок / пропущено
J. Примеры на живом ядре .................. ок / не ок

Замечания:
Источник: insync/docs/portal-check.md — правки туда, сайт пересобирается сам.
CtrlI