Skip to content

Commit 64033f7

Browse files
Pin Schema::create patterns to server MigrationAdoption regex
Adds testPackageMigrationCreateTablesAreDetectableByServerAdoptionPatterns to tests/Unit/migrations/MigrationsTest.php. The test mirrors the two regex patterns recognized by the server-side App\Support\MigrationAdoption ::createdTablesIn() — Schema::create('literal', ...) and Schema::create(self::CONST, ...) with const CONST = 'string'; declared in the same file — and asserts every package migration's Schema::create() call resolves to a recognized table name. If a future migration uses a pattern outside those two (string concatenation, helper call, parent::CONST, dynamic name from config), the test fails closed so the server's BLK-S002 partial-bootstrap recovery cannot regress silently.
1 parent 182f340 commit 64033f7

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

tests/Unit/migrations/MigrationsTest.php

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,103 @@ public function testV2MigrationSlateDoesNotUseSchemaDetectionGuards(): void
6868
);
6969
}
7070

71+
/**
72+
* Mirrors `App\Support\MigrationAdoption::createdTablesIn()` in the
73+
* `durableworkflow/server` package. That class drives BLK-S002 recovery
74+
* by scanning each pending package migration's `Schema::create()` target
75+
* and skipping migrations whose tables already exist on the connection.
76+
* It recognizes only two source patterns:
77+
*
78+
* - `Schema::create('table_name', ...)` — string literal target
79+
* - `Schema::create(self::CONST, ...)` — where `const CONST = 'string';`
80+
* is declared in the same file as a string literal
81+
*
82+
* If a future package migration's `Schema::create()` call falls outside
83+
* those two patterns (string concatenation, helper method call,
84+
* `parent::CONST`, dynamic name from config), the server's parser
85+
* silently resolves to an empty list, the adoption pass skips the
86+
* migration, and a partial-bootstrap retry against an already-created
87+
* table re-surfaces the BLK-S002 "table already exists" failure. This
88+
* contract test fails closed when that drift would happen, so the
89+
* server-side recovery cannot regress without a workflow-side signal.
90+
*/
91+
public function testPackageMigrationCreateTablesAreDetectableByServerAdoptionPatterns(): void
92+
{
93+
$migrationFiles = array_merge(
94+
glob(dirname(__DIR__, 3) . '/src/migrations/2022_*.php') ?: [],
95+
glob(dirname(__DIR__, 3) . '/src/migrations/2026_04_*.php') ?: [],
96+
);
97+
sort($migrationFiles);
98+
99+
$this->assertNotEmpty($migrationFiles);
100+
101+
$undetectable = [];
102+
$totalDetected = 0;
103+
104+
foreach ($migrationFiles as $file) {
105+
$contents = file_get_contents($file);
106+
107+
$this->assertIsString($contents);
108+
109+
$createCount = preg_match_all('/Schema::create\s*\(/', $contents);
110+
111+
if ($createCount === 0) {
112+
continue;
113+
}
114+
115+
$constants = [];
116+
117+
if (preg_match_all("/\\bconst\\s+(\\w+)\\s*=\\s*['\"]([^'\"]+)['\"]/", $contents, $constMatches)) {
118+
$constants = array_combine($constMatches[1], $constMatches[2]);
119+
}
120+
121+
$detected = [];
122+
123+
if (preg_match_all(
124+
"/Schema::create\\(\\s*(?:['\"]([^'\"]+)['\"]|self::(\\w+))/",
125+
$contents,
126+
$createMatches,
127+
)) {
128+
foreach ($createMatches[1] as $i => $literal) {
129+
if ($literal !== '') {
130+
$detected[] = $literal;
131+
132+
continue;
133+
}
134+
135+
$constName = $createMatches[2][$i] ?? '';
136+
137+
if ($constName !== '' && isset($constants[$constName])) {
138+
$detected[] = $constants[$constName];
139+
}
140+
}
141+
}
142+
143+
if (count($detected) !== $createCount) {
144+
$undetectable[] = sprintf(
145+
'%s: %d Schema::create() call(s) but %d recognized by adoption regex',
146+
basename($file),
147+
$createCount,
148+
count($detected),
149+
);
150+
}
151+
152+
$totalDetected += count($detected);
153+
}
154+
155+
$this->assertSame(
156+
[],
157+
$undetectable,
158+
"Every package migration's Schema::create() target must match one of the two patterns "
159+
. 'recognized by App\\Support\\MigrationAdoption::createdTablesIn() in the standalone server: '
160+
. "Schema::create('literal', ...) or Schema::create(self::CONST, ...) "
161+
. "with `const CONST = 'string';` declared in the same file. "
162+
. 'A miss silently regresses BLK-S002 partial-bootstrap recovery.',
163+
);
164+
165+
$this->assertGreaterThan(0, $totalDetected);
166+
}
167+
71168
public function testDownMethodsDropTables(): void
72169
{
73170
$this->assertTrue(Schema::hasTable('workflows'));

0 commit comments

Comments
 (0)