Files
portal/app/tests/Feature/Database/TestDbRebuildGuardTest.php
T
Дмитрий bffca85399 docs+fix: канон схемы догнал миграции — 39 таблиц описаны, сверка считает обе стороны
Канон знал 82 таблицы и 995 столбцов, а база — 121 и 1470: не описаны были
рекламный модуль, телеграм-рассылки и весь отдел продаж.

Главное, что выяснилось по дороге: db/schema.sql не документ, а исполняемый
файл — миграция 0001_01_01_000000_load_initial_schema заливает его целиком
первым шагом сборки. Перенести туда DDL модулей нельзя: те же таблицы создают
дельта-миграции, их 77 и 49 из них без стражей. Сборка с нуля падала дважды.
Поэтому канон разбит на два файла: schema.sql исполняется, новый
schema_modules.sql только описывает.

Проверено не глазами:
- сборка с нуля 148 из 148 DONE;
- столбцы 1470 против 1470, ноль расхождений по имени, типу, длине и NULL;
- все четыре счётчика расхождений инструмента — ноль;
- schema.sql отдельно исполняется без единой ошибки, ограничения 495=495,
  политики 64=64;
- статанализ 0.

Инструмент сверки усилен: считал только одну сторону и потому не видел
переименования jivo_chat_id в chat_id — старое имя жило в каноне месяц.
Теперь обе стороны, канон из нескольких файлов, понимание RENAME/DROP COLUMN
и DROP TABLE. Починен разбор переносов строки внутри определения столбца.

Сторож SchemaDeltaTest дополнен: файл модулей обязан быть на месте и описывать
39 таблиц, а тело schema.sql их не содержать. Принят вырезанием.

Найдено и НЕ исправлено, нужно решение владельца: задвоенный указатель на
deals и пять политик без NULLIF в миграциях. Оба помечены в тексте канона.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 12:53:45 +03:00

47 lines
2.9 KiB
PHP

<?php
declare(strict_types=1);
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
uses(RefreshDatabase::class);
/**
* Сторож против пересборки тестовой БД ПОСРЕДИ прогона.
*
* Laravel заворачивает каждый тест в «черновую» транзакцию, а в конце проверяет, что
* соединение в ней осталось. Если тест черновик закрыл сам, Laravel сбрасывает свой
* признак «БД собрана» (RefreshDatabase.php, строки 158-160) и следующий тест
* пересобирает базу целиком — посреди прогона, снося её под всеми остальными. Отсюда
* и «прогон рвётся через раз», и «таблица X не существует» за сотни шагов от причины.
*
* Tests\TestCase взводит признак на каждом тесте, поэтому пересборки не происходит.
*
* ПРИЁМКА ВЫРЕЗАНИЕМ: убрать строку `RefreshDatabaseState::$migrated = true;` из
* TestCase::setUpTraits() — второй тест этого файла обязан УПАСТЬ (метки не будет,
* потому что базу пересоберут между тестами). Вернуть строку — снова зелёный.
*/
it('ловушка: тест закрывает черновую транзакцию и оставляет метку в БД', function () {
// Именно так ведёт себя боевой код со своими DB::transaction/SET LOCAL —
// здесь мы воспроизводим это нарочно и в чистом виде.
DB::commit();
DB::statement('DROP TABLE IF EXISTS proverka_peresborki');
DB::statement('CREATE TABLE proverka_peresborki (x int)');
expect(Schema::hasTable('proverka_peresborki'))->toBeTrue();
});
it('метка на месте — значит пересборки посреди прогона не было', function () {
expect(Schema::hasTable('proverka_peresborki'))->toBeTrue();
// Снимаем метку НАСОВСЕМ. Без этого DROP уезжает в черновую транзакцию, откат
// её возвращает — и метка остаётся в базе после всего прогона: сторож чистоты
// (tools/storozh-chistoty-bazy.mjs) видел ровно эту одну лишнюю таблицу.
// Приём тот же, что в первом тесте: сначала закрыть черновик, потом писать.
DB::commit();
DB::statement('DROP TABLE IF EXISTS proverka_peresborki');
});