2026-05-01 01:40:27 +00:00
|
|
|
<?php
|
|
|
|
|
|
2026-05-11 11:40:06 +00:00
|
|
|
namespace Tests\Unit\Advisor\Validator;
|
2026-05-01 01:40:27 +00:00
|
|
|
|
2026-05-11 11:40:06 +00:00
|
|
|
use Appwrite\Advisor\Validator\CTAs;
|
2026-05-01 01:40:27 +00:00
|
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
|
|
2026-05-01 02:27:45 +00:00
|
|
|
class CTAsTest extends TestCase
|
2026-05-01 01:40:27 +00:00
|
|
|
{
|
|
|
|
|
public function testRejectsNonArray(): void
|
|
|
|
|
{
|
2026-05-01 02:27:45 +00:00
|
|
|
$validator = new CTAs();
|
2026-05-01 01:40:27 +00:00
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid('not-an-array'));
|
|
|
|
|
$this->assertFalse($validator->isValid(42));
|
|
|
|
|
$this->assertFalse($validator->isValid(null));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testAcceptsEmptyArray(): void
|
|
|
|
|
{
|
2026-05-01 02:27:45 +00:00
|
|
|
$validator = new CTAs();
|
2026-05-01 01:40:27 +00:00
|
|
|
|
|
|
|
|
$this->assertTrue($validator->isValid([]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testAcceptsCompleteEntry(): void
|
|
|
|
|
{
|
2026-05-01 02:27:45 +00:00
|
|
|
$validator = new CTAs();
|
2026-05-01 01:40:27 +00:00
|
|
|
|
|
|
|
|
$this->assertTrue($validator->isValid([[
|
|
|
|
|
'label' => 'Create missing index',
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'createIndex',
|
2026-05-01 01:40:27 +00:00
|
|
|
'params' => [
|
|
|
|
|
'databaseId' => 'main',
|
2026-05-06 04:35:33 +00:00
|
|
|
'tableId' => 'orders',
|
2026-05-01 01:40:27 +00:00
|
|
|
],
|
|
|
|
|
]]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testAcceptsEntryWithoutParams(): void
|
|
|
|
|
{
|
2026-05-01 02:27:45 +00:00
|
|
|
$validator = new CTAs();
|
2026-05-01 01:40:27 +00:00
|
|
|
|
|
|
|
|
$this->assertTrue($validator->isValid([[
|
|
|
|
|
'label' => 'Create missing index',
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'createIndex',
|
2026-05-01 01:40:27 +00:00
|
|
|
]]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testRejectsEntryMissingRequiredKeys(): void
|
|
|
|
|
{
|
2026-05-01 02:27:45 +00:00
|
|
|
$validator = new CTAs();
|
2026-05-01 01:40:27 +00:00
|
|
|
|
refactor(insights): drop CTA `key` field
`key` was a leftover from when CTAs were embedded JSON — there's no
remaining reason to require analyzers to invent a within-insight
identifier. The execution layer is gone (no `cta.key` event format),
insights are immutable from the user side (analyzers re-ingest by
delete + recreate, so idempotent matching never happens), and `label`
already covers human-facing identification. The console can group/sort
CTAs by `service`+`method` if needed.
- Schema: drop `key` attribute and the UNIQUE
`(insightInternalId, key)` index from insightCTAs. Required fields
are now `label`, `service`, `method` (+ optional `params`).
- Validator no longer requires `key`. Drop the dup-key normalization
loop in the manager Create endpoint — there's no semantic
uniqueness to enforce.
- Response model: `InsightCTA` keeps `$id` + standard headers,
`insightId` backref, and the four functional fields.
- E2E: drop sampleCTA's `$key` parameter, drop the
testCreateRejectsDuplicateCTAIds test entirely, rename empty-fields
test to testCreateRejectsCTAWithEmptyLabel and update the missing-
fields tests to drop `key` from their payloads.
- Unit tests rewritten to drop `key`.
- Comment on the `insights.ctas` virtual attribute updated to
reference the renamed `insightCTAs` collection.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 06:29:40 +00:00
|
|
|
$this->assertFalse($validator->isValid([['label' => 'x']]));
|
|
|
|
|
$this->assertFalse($validator->isValid([['label' => 'x', 'service' => 'tablesDB']]));
|
|
|
|
|
$this->assertFalse($validator->isValid([['label' => 'x', 'method' => 'createIndex']]));
|
2026-05-01 01:40:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testRejectsEntryWithEmptyStrings(): void
|
|
|
|
|
{
|
2026-05-01 02:27:45 +00:00
|
|
|
$validator = new CTAs();
|
2026-05-01 01:40:27 +00:00
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid([[
|
refactor(insights): drop CTA `key` field
`key` was a leftover from when CTAs were embedded JSON — there's no
remaining reason to require analyzers to invent a within-insight
identifier. The execution layer is gone (no `cta.key` event format),
insights are immutable from the user side (analyzers re-ingest by
delete + recreate, so idempotent matching never happens), and `label`
already covers human-facing identification. The console can group/sort
CTAs by `service`+`method` if needed.
- Schema: drop `key` attribute and the UNIQUE
`(insightInternalId, key)` index from insightCTAs. Required fields
are now `label`, `service`, `method` (+ optional `params`).
- Validator no longer requires `key`. Drop the dup-key normalization
loop in the manager Create endpoint — there's no semantic
uniqueness to enforce.
- Response model: `InsightCTA` keeps `$id` + standard headers,
`insightId` backref, and the four functional fields.
- E2E: drop sampleCTA's `$key` parameter, drop the
testCreateRejectsDuplicateCTAIds test entirely, rename empty-fields
test to testCreateRejectsCTAWithEmptyLabel and update the missing-
fields tests to drop `key` from their payloads.
- Unit tests rewritten to drop `key`.
- Comment on the `insights.ctas` virtual attribute updated to
reference the renamed `insightCTAs` collection.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 06:29:40 +00:00
|
|
|
'label' => '',
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'createIndex',
|
2026-05-01 01:40:27 +00:00
|
|
|
]]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testRejectsEntryWithNonStringFields(): void
|
|
|
|
|
{
|
2026-05-01 02:27:45 +00:00
|
|
|
$validator = new CTAs();
|
2026-05-01 01:40:27 +00:00
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid([[
|
refactor(insights): drop CTA `key` field
`key` was a leftover from when CTAs were embedded JSON — there's no
remaining reason to require analyzers to invent a within-insight
identifier. The execution layer is gone (no `cta.key` event format),
insights are immutable from the user side (analyzers re-ingest by
delete + recreate, so idempotent matching never happens), and `label`
already covers human-facing identification. The console can group/sort
CTAs by `service`+`method` if needed.
- Schema: drop `key` attribute and the UNIQUE
`(insightInternalId, key)` index from insightCTAs. Required fields
are now `label`, `service`, `method` (+ optional `params`).
- Validator no longer requires `key`. Drop the dup-key normalization
loop in the manager Create endpoint — there's no semantic
uniqueness to enforce.
- Response model: `InsightCTA` keeps `$id` + standard headers,
`insightId` backref, and the four functional fields.
- E2E: drop sampleCTA's `$key` parameter, drop the
testCreateRejectsDuplicateCTAIds test entirely, rename empty-fields
test to testCreateRejectsCTAWithEmptyLabel and update the missing-
fields tests to drop `key` from their payloads.
- Unit tests rewritten to drop `key`.
- Comment on the `insights.ctas` virtual attribute updated to
reference the renamed `insightCTAs` collection.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 06:29:40 +00:00
|
|
|
'label' => 123,
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'createIndex',
|
2026-05-01 01:40:27 +00:00
|
|
|
]]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testRejectsEntryWithScalarParams(): void
|
|
|
|
|
{
|
2026-05-01 02:27:45 +00:00
|
|
|
$validator = new CTAs();
|
2026-05-01 01:40:27 +00:00
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
|
|
|
'label' => 'Create missing index',
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'createIndex',
|
2026-05-01 01:40:27 +00:00
|
|
|
'params' => 'not-a-map',
|
|
|
|
|
]]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testReportsArrayType(): void
|
|
|
|
|
{
|
2026-05-01 02:27:45 +00:00
|
|
|
$validator = new CTAs();
|
2026-05-01 01:40:27 +00:00
|
|
|
|
|
|
|
|
$this->assertTrue($validator->isArray());
|
|
|
|
|
$this->assertSame($validator::TYPE_ARRAY, $validator->getType());
|
|
|
|
|
}
|
refactor(insights): metadata-only CTAs, platform DB, reports parent
Address review feedback on PR #12194:
- Pivot CTAs to pure descriptors (id/label/action/params). Drop the
server-side execution layer: Action interface, registry, the
databases.indexes.create CTA action, the params validator, the
/v1/insights/:id/ctas/:id/executions endpoint, the InsightCTAExecution
model, the INSIGHT_CTA_* errors, and the corresponding events. The
console invokes the existing public API directly with the descriptor's
action + params.
- Restore Databases\Indexes\Action.php to its pre-CTA shape and inline
the index-create body back into Create.php (the createIndex helper
was added solely for CTA reuse).
- Move insights collection from project DB to platform DB and add a
parent reports collection alongside it. Insights carry projectId /
projectInternalId for tenant scoping and an optional reportId for
grouping. List endpoints filter by projectInternalId; Get/Update/
Delete also enforce project ownership before touching the document.
- New Reports module with full CRUD (Create/Get/XList/Update/Delete),
Report response model, Reports query validator, REPORT_NOT_FOUND /
REPORT_ALREADY_EXISTS errors, reports.read / reports.write scopes,
and reports.* event tree. Delete cascades to child insights.
- Update.php now mutates the loaded document via setAttribute (instead
of passing a partial new Document), reuses CTAsValidator (instead of
the looser ArrayList<JSON> + isset check), and rejects duplicate CTA
ids.
- Create.php enforces unique CTA ids during normalization.
- CTAsValidator gained a configurable maxCount (default 16) so the
Create path matches the Update path and the DB column size, and
oversized payloads return a clean 400.
- Validator\Queries\Insights adds status and reportId to
ALLOWED_ATTRIBUTES so dismissal / report workflows are filterable.
- Realtime channel parser guards $parts[1] for both insights and
reports event names.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 01:46:07 +00:00
|
|
|
|
|
|
|
|
public function testRejectsMoreThanMaxCount(): void
|
|
|
|
|
{
|
|
|
|
|
$validator = new CTAs(maxCount: 3);
|
|
|
|
|
|
|
|
|
|
$entries = [];
|
|
|
|
|
for ($i = 0; $i < 4; $i++) {
|
|
|
|
|
$entries[] = [
|
|
|
|
|
'label' => 'Label ' . $i,
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'createIndex',
|
refactor(insights): metadata-only CTAs, platform DB, reports parent
Address review feedback on PR #12194:
- Pivot CTAs to pure descriptors (id/label/action/params). Drop the
server-side execution layer: Action interface, registry, the
databases.indexes.create CTA action, the params validator, the
/v1/insights/:id/ctas/:id/executions endpoint, the InsightCTAExecution
model, the INSIGHT_CTA_* errors, and the corresponding events. The
console invokes the existing public API directly with the descriptor's
action + params.
- Restore Databases\Indexes\Action.php to its pre-CTA shape and inline
the index-create body back into Create.php (the createIndex helper
was added solely for CTA reuse).
- Move insights collection from project DB to platform DB and add a
parent reports collection alongside it. Insights carry projectId /
projectInternalId for tenant scoping and an optional reportId for
grouping. List endpoints filter by projectInternalId; Get/Update/
Delete also enforce project ownership before touching the document.
- New Reports module with full CRUD (Create/Get/XList/Update/Delete),
Report response model, Reports query validator, REPORT_NOT_FOUND /
REPORT_ALREADY_EXISTS errors, reports.read / reports.write scopes,
and reports.* event tree. Delete cascades to child insights.
- Update.php now mutates the loaded document via setAttribute (instead
of passing a partial new Document), reuses CTAsValidator (instead of
the looser ArrayList<JSON> + isset check), and rejects duplicate CTA
ids.
- Create.php enforces unique CTA ids during normalization.
- CTAsValidator gained a configurable maxCount (default 16) so the
Create path matches the Update path and the DB column size, and
oversized payloads return a clean 400.
- Validator\Queries\Insights adds status and reportId to
ALLOWED_ATTRIBUTES so dismissal / report workflows are filterable.
- Realtime channel parser guards $parts[1] for both insights and
reports event names.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 01:46:07 +00:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid($entries));
|
|
|
|
|
$this->assertStringContainsString('maximum of 3', $validator->getDescription());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testAcceptsExactlyMaxCount(): void
|
|
|
|
|
{
|
|
|
|
|
$validator = new CTAs(maxCount: 3);
|
|
|
|
|
|
|
|
|
|
$entries = [];
|
|
|
|
|
for ($i = 0; $i < 3; $i++) {
|
|
|
|
|
$entries[] = [
|
|
|
|
|
'label' => 'Label ' . $i,
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'createIndex',
|
refactor(insights): metadata-only CTAs, platform DB, reports parent
Address review feedback on PR #12194:
- Pivot CTAs to pure descriptors (id/label/action/params). Drop the
server-side execution layer: Action interface, registry, the
databases.indexes.create CTA action, the params validator, the
/v1/insights/:id/ctas/:id/executions endpoint, the InsightCTAExecution
model, the INSIGHT_CTA_* errors, and the corresponding events. The
console invokes the existing public API directly with the descriptor's
action + params.
- Restore Databases\Indexes\Action.php to its pre-CTA shape and inline
the index-create body back into Create.php (the createIndex helper
was added solely for CTA reuse).
- Move insights collection from project DB to platform DB and add a
parent reports collection alongside it. Insights carry projectId /
projectInternalId for tenant scoping and an optional reportId for
grouping. List endpoints filter by projectInternalId; Get/Update/
Delete also enforce project ownership before touching the document.
- New Reports module with full CRUD (Create/Get/XList/Update/Delete),
Report response model, Reports query validator, REPORT_NOT_FOUND /
REPORT_ALREADY_EXISTS errors, reports.read / reports.write scopes,
and reports.* event tree. Delete cascades to child insights.
- Update.php now mutates the loaded document via setAttribute (instead
of passing a partial new Document), reuses CTAsValidator (instead of
the looser ArrayList<JSON> + isset check), and rejects duplicate CTA
ids.
- Create.php enforces unique CTA ids during normalization.
- CTAsValidator gained a configurable maxCount (default 16) so the
Create path matches the Update path and the DB column size, and
oversized payloads return a clean 400.
- Validator\Queries\Insights adds status and reportId to
ALLOWED_ATTRIBUTES so dismissal / report workflows are filterable.
- Realtime channel parser guards $parts[1] for both insights and
reports event names.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 01:46:07 +00:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($validator->isValid($entries));
|
|
|
|
|
}
|
test(insights): full e2e + per-engine CTA action mapping
- Restructure InsightsBase trait with explicit helper methods
(createInsight/getInsight/listInsights/updateInsight/deleteInsight,
createReport/getReport/listReports/updateReport/deleteReport, plus
sampleInsight/sampleCTA factories) — same shape ProxyBase uses.
- Add coverage for: report CRUD + duplicate-id rejection, invalid type
rejection, list filtering by all allowed attributes, cursor
pagination + missing-cursor, update preserving untouched fields,
CTA validation edge cases (duplicate ids, empty fields, count > 16),
dismissal round-trip + status filter, report cascade delete,
unauthorized access (no server key), empty-result list.
- Engine-specific insight types (tablesDBIndex, documentsDBIndex,
vectorsDBIndex, plus the legacy databaseIndex) so the CTA's `action`
can map to the matching public API: databases.createIndex,
tablesDB.createIndex, documentsDB.createIndex,
vectorsDB.createIndex. dataProvider drives the engine matrix and
asserts the right action lands in the persisted CTA. Constants for
each action name live in app/init/constants.php.
- InsightCTA model docs spell out which action belongs to which engine
and that the params keys differ between APIs (tableId/columns for
tablesDB vs collectionId/attributes for the legacy / DocumentsDB /
VectorsDB APIs).
- Insight model `type` description now lists every engine variant.
- CTAsTest gains coverage for object-shaped params, empty-action and
empty-label rejection, and the default 16-entry cap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 04:25:49 +00:00
|
|
|
|
|
|
|
|
public function testAcceptsObjectParams(): void
|
|
|
|
|
{
|
|
|
|
|
$validator = new CTAs();
|
|
|
|
|
|
|
|
|
|
$entry = [
|
|
|
|
|
'label' => 'Create missing index',
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'createIndex',
|
test(insights): full e2e + per-engine CTA action mapping
- Restructure InsightsBase trait with explicit helper methods
(createInsight/getInsight/listInsights/updateInsight/deleteInsight,
createReport/getReport/listReports/updateReport/deleteReport, plus
sampleInsight/sampleCTA factories) — same shape ProxyBase uses.
- Add coverage for: report CRUD + duplicate-id rejection, invalid type
rejection, list filtering by all allowed attributes, cursor
pagination + missing-cursor, update preserving untouched fields,
CTA validation edge cases (duplicate ids, empty fields, count > 16),
dismissal round-trip + status filter, report cascade delete,
unauthorized access (no server key), empty-result list.
- Engine-specific insight types (tablesDBIndex, documentsDBIndex,
vectorsDBIndex, plus the legacy databaseIndex) so the CTA's `action`
can map to the matching public API: databases.createIndex,
tablesDB.createIndex, documentsDB.createIndex,
vectorsDB.createIndex. dataProvider drives the engine matrix and
asserts the right action lands in the persisted CTA. Constants for
each action name live in app/init/constants.php.
- InsightCTA model docs spell out which action belongs to which engine
and that the params keys differ between APIs (tableId/columns for
tablesDB vs collectionId/attributes for the legacy / DocumentsDB /
VectorsDB APIs).
- Insight model `type` description now lists every engine variant.
- CTAsTest gains coverage for object-shaped params, empty-action and
empty-label rejection, and the default 16-entry cap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 04:25:49 +00:00
|
|
|
'params' => new \stdClass(),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($validator->isValid([$entry]));
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-06 04:35:33 +00:00
|
|
|
public function testRejectsEntryWithEmptyService(): void
|
test(insights): full e2e + per-engine CTA action mapping
- Restructure InsightsBase trait with explicit helper methods
(createInsight/getInsight/listInsights/updateInsight/deleteInsight,
createReport/getReport/listReports/updateReport/deleteReport, plus
sampleInsight/sampleCTA factories) — same shape ProxyBase uses.
- Add coverage for: report CRUD + duplicate-id rejection, invalid type
rejection, list filtering by all allowed attributes, cursor
pagination + missing-cursor, update preserving untouched fields,
CTA validation edge cases (duplicate ids, empty fields, count > 16),
dismissal round-trip + status filter, report cascade delete,
unauthorized access (no server key), empty-result list.
- Engine-specific insight types (tablesDBIndex, documentsDBIndex,
vectorsDBIndex, plus the legacy databaseIndex) so the CTA's `action`
can map to the matching public API: databases.createIndex,
tablesDB.createIndex, documentsDB.createIndex,
vectorsDB.createIndex. dataProvider drives the engine matrix and
asserts the right action lands in the persisted CTA. Constants for
each action name live in app/init/constants.php.
- InsightCTA model docs spell out which action belongs to which engine
and that the params keys differ between APIs (tableId/columns for
tablesDB vs collectionId/attributes for the legacy / DocumentsDB /
VectorsDB APIs).
- Insight model `type` description now lists every engine variant.
- CTAsTest gains coverage for object-shaped params, empty-action and
empty-label rejection, and the default 16-entry cap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 04:25:49 +00:00
|
|
|
{
|
|
|
|
|
$validator = new CTAs();
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
|
|
|
'label' => 'Create missing index',
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => '',
|
|
|
|
|
'method' => 'createIndex',
|
|
|
|
|
]]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testRejectsEntryWithEmptyMethod(): void
|
|
|
|
|
{
|
|
|
|
|
$validator = new CTAs();
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
|
|
|
'label' => 'Create missing index',
|
|
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => '',
|
test(insights): full e2e + per-engine CTA action mapping
- Restructure InsightsBase trait with explicit helper methods
(createInsight/getInsight/listInsights/updateInsight/deleteInsight,
createReport/getReport/listReports/updateReport/deleteReport, plus
sampleInsight/sampleCTA factories) — same shape ProxyBase uses.
- Add coverage for: report CRUD + duplicate-id rejection, invalid type
rejection, list filtering by all allowed attributes, cursor
pagination + missing-cursor, update preserving untouched fields,
CTA validation edge cases (duplicate ids, empty fields, count > 16),
dismissal round-trip + status filter, report cascade delete,
unauthorized access (no server key), empty-result list.
- Engine-specific insight types (tablesDBIndex, documentsDBIndex,
vectorsDBIndex, plus the legacy databaseIndex) so the CTA's `action`
can map to the matching public API: databases.createIndex,
tablesDB.createIndex, documentsDB.createIndex,
vectorsDB.createIndex. dataProvider drives the engine matrix and
asserts the right action lands in the persisted CTA. Constants for
each action name live in app/init/constants.php.
- InsightCTA model docs spell out which action belongs to which engine
and that the params keys differ between APIs (tableId/columns for
tablesDB vs collectionId/attributes for the legacy / DocumentsDB /
VectorsDB APIs).
- Insight model `type` description now lists every engine variant.
- CTAsTest gains coverage for object-shaped params, empty-action and
empty-label rejection, and the default 16-entry cap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 04:25:49 +00:00
|
|
|
]]));
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-12 13:42:59 +00:00
|
|
|
public function testRejectsUnknownService(): void
|
|
|
|
|
{
|
|
|
|
|
$validator = new CTAs();
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
|
|
|
'label' => 'Create missing index',
|
|
|
|
|
'service' => 'nonExistentService',
|
|
|
|
|
'method' => 'createIndex',
|
|
|
|
|
]]));
|
|
|
|
|
$this->assertStringContainsString('service', $validator->getDescription());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testRejectsUnknownMethod(): void
|
|
|
|
|
{
|
|
|
|
|
$validator = new CTAs();
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
|
|
|
'label' => 'Create missing index',
|
|
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'nonExistentMethod',
|
|
|
|
|
]]));
|
|
|
|
|
$this->assertStringContainsString('method', $validator->getDescription());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function testAcceptsCustomAllowedLists(): void
|
|
|
|
|
{
|
|
|
|
|
$validator = new CTAs(
|
|
|
|
|
allowedServices: ['custom'],
|
|
|
|
|
allowedMethods: ['doThing'],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($validator->isValid([[
|
|
|
|
|
'label' => 'Custom action',
|
|
|
|
|
'service' => 'custom',
|
|
|
|
|
'method' => 'doThing',
|
|
|
|
|
]]));
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
|
|
|
'label' => 'Custom action',
|
|
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'doThing',
|
|
|
|
|
]]));
|
|
|
|
|
}
|
|
|
|
|
|
test(insights): full e2e + per-engine CTA action mapping
- Restructure InsightsBase trait with explicit helper methods
(createInsight/getInsight/listInsights/updateInsight/deleteInsight,
createReport/getReport/listReports/updateReport/deleteReport, plus
sampleInsight/sampleCTA factories) — same shape ProxyBase uses.
- Add coverage for: report CRUD + duplicate-id rejection, invalid type
rejection, list filtering by all allowed attributes, cursor
pagination + missing-cursor, update preserving untouched fields,
CTA validation edge cases (duplicate ids, empty fields, count > 16),
dismissal round-trip + status filter, report cascade delete,
unauthorized access (no server key), empty-result list.
- Engine-specific insight types (tablesDBIndex, documentsDBIndex,
vectorsDBIndex, plus the legacy databaseIndex) so the CTA's `action`
can map to the matching public API: databases.createIndex,
tablesDB.createIndex, documentsDB.createIndex,
vectorsDB.createIndex. dataProvider drives the engine matrix and
asserts the right action lands in the persisted CTA. Constants for
each action name live in app/init/constants.php.
- InsightCTA model docs spell out which action belongs to which engine
and that the params keys differ between APIs (tableId/columns for
tablesDB vs collectionId/attributes for the legacy / DocumentsDB /
VectorsDB APIs).
- Insight model `type` description now lists every engine variant.
- CTAsTest gains coverage for object-shaped params, empty-action and
empty-label rejection, and the default 16-entry cap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 04:25:49 +00:00
|
|
|
public function testDefaultMaxCountIsSixteen(): void
|
|
|
|
|
{
|
|
|
|
|
$validator = new CTAs();
|
|
|
|
|
|
|
|
|
|
$this->assertSame(CTAs::MAX_COUNT_DEFAULT, 16);
|
|
|
|
|
|
|
|
|
|
$entries = [];
|
|
|
|
|
for ($i = 0; $i < 16; $i++) {
|
|
|
|
|
$entries[] = [
|
|
|
|
|
'label' => 'Label ' . $i,
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'createIndex',
|
test(insights): full e2e + per-engine CTA action mapping
- Restructure InsightsBase trait with explicit helper methods
(createInsight/getInsight/listInsights/updateInsight/deleteInsight,
createReport/getReport/listReports/updateReport/deleteReport, plus
sampleInsight/sampleCTA factories) — same shape ProxyBase uses.
- Add coverage for: report CRUD + duplicate-id rejection, invalid type
rejection, list filtering by all allowed attributes, cursor
pagination + missing-cursor, update preserving untouched fields,
CTA validation edge cases (duplicate ids, empty fields, count > 16),
dismissal round-trip + status filter, report cascade delete,
unauthorized access (no server key), empty-result list.
- Engine-specific insight types (tablesDBIndex, documentsDBIndex,
vectorsDBIndex, plus the legacy databaseIndex) so the CTA's `action`
can map to the matching public API: databases.createIndex,
tablesDB.createIndex, documentsDB.createIndex,
vectorsDB.createIndex. dataProvider drives the engine matrix and
asserts the right action lands in the persisted CTA. Constants for
each action name live in app/init/constants.php.
- InsightCTA model docs spell out which action belongs to which engine
and that the params keys differ between APIs (tableId/columns for
tablesDB vs collectionId/attributes for the legacy / DocumentsDB /
VectorsDB APIs).
- Insight model `type` description now lists every engine variant.
- CTAsTest gains coverage for object-shaped params, empty-action and
empty-label rejection, and the default 16-entry cap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 04:25:49 +00:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->assertTrue($validator->isValid($entries));
|
|
|
|
|
|
|
|
|
|
$entries[] = [
|
|
|
|
|
'label' => 'Label 16',
|
2026-05-06 04:35:33 +00:00
|
|
|
'service' => 'tablesDB',
|
|
|
|
|
'method' => 'createIndex',
|
test(insights): full e2e + per-engine CTA action mapping
- Restructure InsightsBase trait with explicit helper methods
(createInsight/getInsight/listInsights/updateInsight/deleteInsight,
createReport/getReport/listReports/updateReport/deleteReport, plus
sampleInsight/sampleCTA factories) — same shape ProxyBase uses.
- Add coverage for: report CRUD + duplicate-id rejection, invalid type
rejection, list filtering by all allowed attributes, cursor
pagination + missing-cursor, update preserving untouched fields,
CTA validation edge cases (duplicate ids, empty fields, count > 16),
dismissal round-trip + status filter, report cascade delete,
unauthorized access (no server key), empty-result list.
- Engine-specific insight types (tablesDBIndex, documentsDBIndex,
vectorsDBIndex, plus the legacy databaseIndex) so the CTA's `action`
can map to the matching public API: databases.createIndex,
tablesDB.createIndex, documentsDB.createIndex,
vectorsDB.createIndex. dataProvider drives the engine matrix and
asserts the right action lands in the persisted CTA. Constants for
each action name live in app/init/constants.php.
- InsightCTA model docs spell out which action belongs to which engine
and that the params keys differ between APIs (tableId/columns for
tablesDB vs collectionId/attributes for the legacy / DocumentsDB /
VectorsDB APIs).
- Insight model `type` description now lists every engine variant.
- CTAsTest gains coverage for object-shaped params, empty-action and
empty-label rejection, and the default 16-entry cap.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 04:25:49 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$this->assertFalse($validator->isValid($entries));
|
|
|
|
|
}
|
2026-05-01 01:40:27 +00:00
|
|
|
}
|