fix(tests): sync 3 stale эпик-тестов + schema.sql header под Plans 1-3 (v8.26)
Три pre-existing красных теста (ЭТАЛОН §6 «deferred») приведены к реальной схеме v8.26 после project-migration-redesign Plans 1-3: - SchemaDeltaTest: 64→65 base tables, 121→123 indexes (project_supplier_links pivot + supplier_projects_platform_key_subject_unique). - SupplierProjectsAccessTest: unique-constraint (platform, unique_key) → (platform, unique_key, subject_code) — per-субъект экспорт (Plan 1). - SupplierLeadFlowTest: routing eligibility теперь через pivot project_supplier_links (LeadRouter), не legacy supplier_b1_project_id — добавлены linkProjectToSupplier() связи. - schema.sql header: v8.25→v8.26 + метрики (CHANGELOG уже содержал v8.26). Production-код не менялся — тесты отставали от уже-смердженных Plans 1-3. Pest full 1013/1010 passed/3 skipped/0 failed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,7 +36,7 @@ it('end-to-end: 1 webhook → 3 deal copies for 3 active tenants', function ():
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$t = Tenant::factory()->create(['balance_leads' => 100]);
|
||||
$tenants->push($t);
|
||||
$projects->push(Project::factory()->create([
|
||||
$project = Project::factory()->create([
|
||||
'tenant_id' => $t->id,
|
||||
'supplier_b1_project_id' => $supplier->id,
|
||||
'signal_type' => 'site',
|
||||
@@ -49,18 +49,24 @@ it('end-to-end: 1 webhook → 3 deal copies for 3 active tenants', function ():
|
||||
'region_mode' => 'include',
|
||||
'daily_limit_target' => 10,
|
||||
'effective_daily_limit_today' => null,
|
||||
]));
|
||||
]);
|
||||
$projects->push($project);
|
||||
// v8.26 (Plan 1-2): LeadRouter eligibility — через pivot project_supplier_links,
|
||||
// не legacy supplier_b1_project_id. Без pivot-связи проект не eligible → 0 сделок.
|
||||
linkProjectToSupplier($project, $supplier);
|
||||
}
|
||||
|
||||
// 4-й tenant — paused
|
||||
// 4-й tenant — paused (is_active=false). Связь в pivot есть, чтобы проверялся
|
||||
// именно фильтр is_active, а не отсутствие связи.
|
||||
$pausedTenant = Tenant::factory()->create(['balance_leads' => 100]);
|
||||
Project::factory()->create([
|
||||
$pausedProject = Project::factory()->create([
|
||||
'tenant_id' => $pausedTenant->id,
|
||||
'supplier_b1_project_id' => $supplier->id,
|
||||
'signal_type' => 'site',
|
||||
'signal_identifier' => 'vashinvestor.ru',
|
||||
'is_active' => false,
|
||||
]);
|
||||
linkProjectToSupplier($pausedProject, $supplier);
|
||||
|
||||
$vid = 432176649;
|
||||
$response = $this->postJson('/api/webhook/supplier/test-secret-32chars-aaaaaaaaaaaaaa', [
|
||||
|
||||
@@ -27,19 +27,23 @@ test('supplier_projects table exists with required columns', function () {
|
||||
}
|
||||
});
|
||||
|
||||
test('supplier_projects has unique constraint on (platform, unique_key)', function () {
|
||||
test('supplier_projects has unique constraint on (platform, unique_key, subject_code)', function () {
|
||||
// v8.26 (project-migration-redesign Plan 1): per-субъект экспорт — composite unique
|
||||
// расширен до (platform, unique_key, subject_code) NULLS NOT DISTINCT. Старый
|
||||
// 2-колоночный индекс supplier_projects_platform_unique_key_unique заменён.
|
||||
$idx = DB::selectOne(
|
||||
"SELECT indexdef
|
||||
FROM pg_indexes
|
||||
WHERE tablename = 'supplier_projects'
|
||||
AND indexname = 'supplier_projects_platform_unique_key_unique'"
|
||||
AND indexname = 'supplier_projects_platform_key_subject_unique'"
|
||||
);
|
||||
|
||||
expect($idx)->not->toBeNull();
|
||||
expect($idx->indexdef)
|
||||
->toContain('UNIQUE')
|
||||
->toContain('platform')
|
||||
->toContain('unique_key');
|
||||
->toContain('unique_key')
|
||||
->toContain('subject_code');
|
||||
});
|
||||
|
||||
test('supplier_projects platform check constraint allows only B1, B2, B3', function () {
|
||||
|
||||
@@ -59,26 +59,28 @@ it('supplier_csv_reconcile_log table exists with required columns and status CHE
|
||||
]))->toThrow(QueryException::class);
|
||||
});
|
||||
|
||||
it('schema.sql v8.25 has correct metrics — 64 base tables, 121 indexes, 40 RLS policies', function () {
|
||||
it('schema.sql v8.26 has correct metrics — 65 base tables, 123 indexes, 40 RLS policies', function () {
|
||||
// Замена destructive `migrate:fresh` (cross-test coupling: после DROP CASCADE остальные
|
||||
// Feature-тесты в той же сессии видели пустую БД). Static parse `db/schema.sql` —
|
||||
// источник истины метрик из spec §2.4 / db/CHANGELOG_schema.md v8.25.
|
||||
// источник истины метрик из spec §2.4 / db/CHANGELOG_schema.md v8.26.
|
||||
// v8.21 (Sprint 4): +1 таблица import_unknown_statuses, +1 индекс, +1 RLS-политика.
|
||||
// v8.22 (Plan 6/C9): +1 GIN-индекс idx_projects_regions.
|
||||
// v8.25 (supplier-failover): +1 таблица supplier_manual_sync_queue, +2 индекса.
|
||||
// v8.26 (project-migration-redesign Plans 1-3): +1 таблица project_supplier_links (M:N pivot)
|
||||
// + 2 индекса (supplier_projects_platform_key_subject_unique, idx_psl_*).
|
||||
$schemaPath = dirname(base_path()).DIRECTORY_SEPARATOR.'db'.DIRECTORY_SEPARATOR.'schema.sql';
|
||||
expect(is_file($schemaPath) && is_readable($schemaPath))->toBeTrue();
|
||||
$schema = file_get_contents($schemaPath);
|
||||
expect($schema)->not->toBeFalse();
|
||||
|
||||
// 64 base tables = все CREATE TABLE минус 12 партиций (PARTITION OF).
|
||||
// 65 base tables = все CREATE TABLE минус 12 партиций (PARTITION OF).
|
||||
$createTables = preg_match_all('/^CREATE TABLE\b/m', $schema);
|
||||
$partitionOf = preg_match_all('/CREATE TABLE\s+\w+\s+PARTITION OF\b/m', $schema);
|
||||
$baseTables = $createTables - $partitionOf;
|
||||
expect($baseTables)->toBe(64);
|
||||
expect($baseTables)->toBe(65);
|
||||
|
||||
$createIndexes = preg_match_all('/^CREATE\s+(?:UNIQUE\s+)?INDEX\b/m', $schema);
|
||||
expect($createIndexes)->toBe(121); // v8.25: +2 idx_smsq_status_created, idx_smsq_project
|
||||
expect($createIndexes)->toBe(123); // v8.26: +2 supplier_projects_platform_key_subject_unique, idx_psl_*
|
||||
|
||||
$createPolicies = preg_match_all('/^CREATE\s+POLICY\b/m', $schema);
|
||||
expect($createPolicies)->toBe(40);
|
||||
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
-- =============================================================================
|
||||
-- schema.sql — единая схема БД для SaaS-аналога crm.bp-gr.ru («Лидерра»)
|
||||
-- Версия: v8.25 (19.05.2026 — supplier_manual_sync_queue: SaaS-level Tier 3 очередь резерва канала миграции проектов)
|
||||
-- Метрики: 64 базовые таблицы (62 regular + 2 partitioned parents: deals + supplier_lead_costs) + 12 партиций / 121 индекс / 40 RLS-политик / 5 функций / 13 триггеров
|
||||
-- Версия: v8.26 (20.05.2026 — project-migration-redesign Plans 1-3: supplier_projects.subject_code (per-субъект экспорт) + project_supplier_links (M:N pivot projects↔supplier_projects) + deals.subject_code + CHECK chk_deals_subject_code + seed system_settings.supplier_export_mode)
|
||||
-- Метрики: 65 базовые таблицы (63 regular + 2 partitioned parents: deals + supplier_lead_costs) + 12 партиций / 123 индекса / 40 RLS-политик / 5 функций / 13 триггеров
|
||||
-- Базовая версия: v8.25 (19.05.2026 — supplier_manual_sync_queue: SaaS-level Tier 3 очередь резерва канала миграции проектов)
|
||||
-- Базовая версия: v8.24 (18.05.2026 — supplier_leads.vid → nullable для CSV-recovered лидов (Путь 2))
|
||||
-- Базовая версия: v8.20 (11.05.2026 — Plan 5 frontend projects UI: projects.archived_at TIMESTAMPTZ NULL для soft archive flow; tenants.limits JSONB NOT NULL DEFAULT '{}' для per-tenant project/user лимитов)
|
||||
-- Базовая версия: v8.19 (11.05.2026 — Plan 4 billing+csv+admin: tenants.delivered_in_month, lead_charges.charge_source + CHECK, supplier_leads.recovered_from_csv_at, supplier_csv_reconcile_log)
|
||||
|
||||
Reference in New Issue
Block a user