appwrite/tests/e2e/Services/Advisor/AdvisorBase.php

123 lines
4.2 KiB
PHP
Raw Permalink Normal View History

<?php
namespace Tests\E2E\Services\Advisor;
use Tests\E2E\Client;
use Utopia\Database\Helpers\ID;
trait AdvisorBase
{
protected function serverHeaders(): array
{
return [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
];
}
test(insights): fix CI failures from nesting refactor Three breakages on the prior CI run: 1. PHPUnit 12 didn't propagate `@depends` data — chained tests got ArgumentCountError because they expected `array $data` but PHPUnit passed nothing. Convert all annotations to `#[Depends]` attributes, matching the modern style already used by the Migrations and VectorsDB suites. 2. `InsightsCustomConsoleTest` extends ProjectConsole, which doesn't set up a project API key. The trait's `serverHeaders()` hardcodes `x-appwrite-key`, so every Console test 401'd. Drop the Console class entirely — the manager Create endpoint is KEY-only by design, the Server class already exercises every code path, and a Console-side variant adds no real coverage. 3. `testCreateRequiresManagerScope` called `getNewKey()`, which lives on `ProjectCustom`. PHPStan flagged the call as undefined when the trait was analyzed against the (no-longer-existing) Console class. Move the test into `InsightsCustomServerTest.php` directly so it's only ever resolved against `ProjectCustom`. Plus PHP 8.4 + match-exhaustive cleanups PHPStan caught while I was in there: - `?array $headers = null` instead of `array $headers = null` on every helper (PHP 8.4 deprecates implicit-nullable params). - `?string $insightId = null` on `sampleInsight()`. - `parentResourceType` match collapsed to `tablesDB => 'tables'; databases/documentsDB/vectorsDB => 'collections'`. The earlier `$type` match already throws on unknown engine, so the fall-through default was unreachable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 08:20:54 +00:00
protected function getReport(string $reportId, ?array $headers = null): array
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
{
return $this->client->call(Client::METHOD_GET, '/reports/' . $reportId, $headers ?? $this->serverHeaders());
}
test(insights): fix CI failures from nesting refactor Three breakages on the prior CI run: 1. PHPUnit 12 didn't propagate `@depends` data — chained tests got ArgumentCountError because they expected `array $data` but PHPUnit passed nothing. Convert all annotations to `#[Depends]` attributes, matching the modern style already used by the Migrations and VectorsDB suites. 2. `InsightsCustomConsoleTest` extends ProjectConsole, which doesn't set up a project API key. The trait's `serverHeaders()` hardcodes `x-appwrite-key`, so every Console test 401'd. Drop the Console class entirely — the manager Create endpoint is KEY-only by design, the Server class already exercises every code path, and a Console-side variant adds no real coverage. 3. `testCreateRequiresManagerScope` called `getNewKey()`, which lives on `ProjectCustom`. PHPStan flagged the call as undefined when the trait was analyzed against the (no-longer-existing) Console class. Move the test into `InsightsCustomServerTest.php` directly so it's only ever resolved against `ProjectCustom`. Plus PHP 8.4 + match-exhaustive cleanups PHPStan caught while I was in there: - `?array $headers = null` instead of `array $headers = null` on every helper (PHP 8.4 deprecates implicit-nullable params). - `?string $insightId = null` on `sampleInsight()`. - `parentResourceType` match collapsed to `tablesDB => 'tables'; databases/documentsDB/vectorsDB => 'collections'`. The earlier `$type` match already throws on unknown engine, so the fall-through default was unreachable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 08:20:54 +00:00
protected function listReports(array $params = [], ?array $headers = null): array
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
{
return $this->client->call(Client::METHOD_GET, '/reports', $headers ?? $this->serverHeaders(), $params);
}
test(insights): fix CI failures from nesting refactor Three breakages on the prior CI run: 1. PHPUnit 12 didn't propagate `@depends` data — chained tests got ArgumentCountError because they expected `array $data` but PHPUnit passed nothing. Convert all annotations to `#[Depends]` attributes, matching the modern style already used by the Migrations and VectorsDB suites. 2. `InsightsCustomConsoleTest` extends ProjectConsole, which doesn't set up a project API key. The trait's `serverHeaders()` hardcodes `x-appwrite-key`, so every Console test 401'd. Drop the Console class entirely — the manager Create endpoint is KEY-only by design, the Server class already exercises every code path, and a Console-side variant adds no real coverage. 3. `testCreateRequiresManagerScope` called `getNewKey()`, which lives on `ProjectCustom`. PHPStan flagged the call as undefined when the trait was analyzed against the (no-longer-existing) Console class. Move the test into `InsightsCustomServerTest.php` directly so it's only ever resolved against `ProjectCustom`. Plus PHP 8.4 + match-exhaustive cleanups PHPStan caught while I was in there: - `?array $headers = null` instead of `array $headers = null` on every helper (PHP 8.4 deprecates implicit-nullable params). - `?string $insightId = null` on `sampleInsight()`. - `parentResourceType` match collapsed to `tablesDB => 'tables'; databases/documentsDB/vectorsDB => 'collections'`. The earlier `$type` match already throws on unknown engine, so the fall-through default was unreachable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 08:20:54 +00:00
protected function getInsight(string $reportId, string $insightId, ?array $headers = null): array
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
{
refactor(insights): nest insights API under reports Insights are children of reports — make the URL hierarchy reflect that. Endpoints: - POST /v1/manager/reports/:reportId/insights (manager Create) - GET /v1/reports/:reportId/insights (List) - GET /v1/reports/:reportId/insights/:insightId (Get) - PATCH /v1/reports/:reportId/insights/:insightId (Update) - DELETE /v1/reports/:reportId/insights/:insightId (Delete) `reportId` moves from optional body field to required path param. All endpoints fetch the report first (404 REPORT_NOT_FOUND if missing or in another project), then verify the insight's `reportInternalId` matches before doing anything else. Side effects: - Event names nested: `reports.[reportId].insights.[insightId].create` etc. Top-level `insights.*` event tree removed from events.php. - Realtime channel parser handles the nested form: a `reports.{rid}` event lights up `reports`, `reports.{rid}` channels; a nested `reports.{rid}.insights.{iid}` event also lights up `reports.{rid}.insights` and `reports.{rid}.insights.{iid}`. - Audit resource paths nested similarly: `report/{request.reportId}/insight/{response.$id}`. - listInsights query validator drops `reportId` from ALLOWED_ATTRIBUTES — it's path-scoped now, not a query filter. Tests: - E2E helpers `createInsight`/`getInsight`/`listInsights`/ `updateInsight`/`deleteInsight` all take `reportId` as the first argument. - New `createFixtureReport()` helper for standalone validation tests that need a parent. - Dropped `testCreateWithoutReport` — reportId is mandatory now. - `testCreateRejectsUnknownReport` now exercises the path-level 404 rather than a body-level check. - `testGet` and `testUpdateMissing` exercise the wrong-reportId-but-valid-insightId case (returns `report_not_found`). - `testList` asserts every result carries the path's reportId, plus a 404 case for a nonexistent parent. - `testCreateForEachEngine` and the standalone create-rejection tests inline-create their own fixture report and clean up after. - `testListSurvivesEmptyDatabase` renamed to `testListSurvivesEmptyReport` and uses a fresh fixture report. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 06:53:54 +00:00
return $this->client->call(Client::METHOD_GET, '/reports/' . $reportId . '/insights/' . $insightId, $headers ?? $this->serverHeaders());
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
}
test(insights): fix CI failures from nesting refactor Three breakages on the prior CI run: 1. PHPUnit 12 didn't propagate `@depends` data — chained tests got ArgumentCountError because they expected `array $data` but PHPUnit passed nothing. Convert all annotations to `#[Depends]` attributes, matching the modern style already used by the Migrations and VectorsDB suites. 2. `InsightsCustomConsoleTest` extends ProjectConsole, which doesn't set up a project API key. The trait's `serverHeaders()` hardcodes `x-appwrite-key`, so every Console test 401'd. Drop the Console class entirely — the manager Create endpoint is KEY-only by design, the Server class already exercises every code path, and a Console-side variant adds no real coverage. 3. `testCreateRequiresManagerScope` called `getNewKey()`, which lives on `ProjectCustom`. PHPStan flagged the call as undefined when the trait was analyzed against the (no-longer-existing) Console class. Move the test into `InsightsCustomServerTest.php` directly so it's only ever resolved against `ProjectCustom`. Plus PHP 8.4 + match-exhaustive cleanups PHPStan caught while I was in there: - `?array $headers = null` instead of `array $headers = null` on every helper (PHP 8.4 deprecates implicit-nullable params). - `?string $insightId = null` on `sampleInsight()`. - `parentResourceType` match collapsed to `tablesDB => 'tables'; databases/documentsDB/vectorsDB => 'collections'`. The earlier `$type` match already throws on unknown engine, so the fall-through default was unreachable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 08:20:54 +00:00
protected function listInsights(string $reportId, array $params = [], ?array $headers = null): array
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
{
refactor(insights): nest insights API under reports Insights are children of reports — make the URL hierarchy reflect that. Endpoints: - POST /v1/manager/reports/:reportId/insights (manager Create) - GET /v1/reports/:reportId/insights (List) - GET /v1/reports/:reportId/insights/:insightId (Get) - PATCH /v1/reports/:reportId/insights/:insightId (Update) - DELETE /v1/reports/:reportId/insights/:insightId (Delete) `reportId` moves from optional body field to required path param. All endpoints fetch the report first (404 REPORT_NOT_FOUND if missing or in another project), then verify the insight's `reportInternalId` matches before doing anything else. Side effects: - Event names nested: `reports.[reportId].insights.[insightId].create` etc. Top-level `insights.*` event tree removed from events.php. - Realtime channel parser handles the nested form: a `reports.{rid}` event lights up `reports`, `reports.{rid}` channels; a nested `reports.{rid}.insights.{iid}` event also lights up `reports.{rid}.insights` and `reports.{rid}.insights.{iid}`. - Audit resource paths nested similarly: `report/{request.reportId}/insight/{response.$id}`. - listInsights query validator drops `reportId` from ALLOWED_ATTRIBUTES — it's path-scoped now, not a query filter. Tests: - E2E helpers `createInsight`/`getInsight`/`listInsights`/ `updateInsight`/`deleteInsight` all take `reportId` as the first argument. - New `createFixtureReport()` helper for standalone validation tests that need a parent. - Dropped `testCreateWithoutReport` — reportId is mandatory now. - `testCreateRejectsUnknownReport` now exercises the path-level 404 rather than a body-level check. - `testGet` and `testUpdateMissing` exercise the wrong-reportId-but-valid-insightId case (returns `report_not_found`). - `testList` asserts every result carries the path's reportId, plus a 404 case for a nonexistent parent. - `testCreateForEachEngine` and the standalone create-rejection tests inline-create their own fixture report and clean up after. - `testListSurvivesEmptyDatabase` renamed to `testListSurvivesEmptyReport` and uses a fresh fixture report. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 06:53:54 +00:00
return $this->client->call(Client::METHOD_GET, '/reports/' . $reportId . '/insights', $headers ?? $this->serverHeaders(), $params);
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 testListReports(): void
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
{
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
$list = $this->listReports();
$this->assertSame(200, $list['headers']['status-code']);
$this->assertArrayHasKey('reports', $list['body']);
$this->assertArrayHasKey('total', $list['body']);
$this->assertIsArray($list['body']['reports']);
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 testGetReportMissing(): 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
{
$missing = $this->getReport(ID::unique());
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->assertSame(404, $missing['headers']['status-code']);
$this->assertSame('report_not_found', $missing['body']['type']);
}
public function testListInsightsMissingReport(): void
{
$missing = $this->listInsights(ID::unique());
$this->assertSame(404, $missing['headers']['status-code']);
$this->assertSame('report_not_found', $missing['body']['type']);
}
public function testGetInsightMissingReport(): void
{
$missing = $this->getInsight(ID::unique(), ID::unique());
$this->assertSame(404, $missing['headers']['status-code']);
$this->assertSame('report_not_found', $missing['body']['type']);
}
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 testReportsCreateAndUpdateNotExposed(): void
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
{
$create = $this->client->call(Client::METHOD_POST, '/reports', $this->serverHeaders(), [
'reportId' => ID::unique(),
'type' => 'audit',
'title' => 'Read-only check',
'targetType' => 'sites',
'target' => 'home',
]);
$this->assertSame(404, $create['headers']['status-code']);
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
$update = $this->client->call(Client::METHOD_PATCH, '/reports/' . ID::unique(), $this->serverHeaders(), [
'title' => 'Read-only check',
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->assertSame(404, $update['headers']['status-code']);
}
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 testDeleteReportMissing(): void
{
$delete = $this->client->call(Client::METHOD_DELETE, '/reports/' . ID::unique(), $this->serverHeaders());
$this->assertSame(404, $delete['headers']['status-code']);
$this->assertSame('report_not_found', $delete['body']['type']);
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 testInsightsCreateUpdateDeleteNotExposed(): 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
{
$create = $this->client->call(
Client::METHOD_POST,
'/reports/' . ID::unique() . '/insights',
$this->serverHeaders(),
[]
);
$this->assertSame(404, $create['headers']['status-code']);
refactor(insights): nest insights API under reports Insights are children of reports — make the URL hierarchy reflect that. Endpoints: - POST /v1/manager/reports/:reportId/insights (manager Create) - GET /v1/reports/:reportId/insights (List) - GET /v1/reports/:reportId/insights/:insightId (Get) - PATCH /v1/reports/:reportId/insights/:insightId (Update) - DELETE /v1/reports/:reportId/insights/:insightId (Delete) `reportId` moves from optional body field to required path param. All endpoints fetch the report first (404 REPORT_NOT_FOUND if missing or in another project), then verify the insight's `reportInternalId` matches before doing anything else. Side effects: - Event names nested: `reports.[reportId].insights.[insightId].create` etc. Top-level `insights.*` event tree removed from events.php. - Realtime channel parser handles the nested form: a `reports.{rid}` event lights up `reports`, `reports.{rid}` channels; a nested `reports.{rid}.insights.{iid}` event also lights up `reports.{rid}.insights` and `reports.{rid}.insights.{iid}`. - Audit resource paths nested similarly: `report/{request.reportId}/insight/{response.$id}`. - listInsights query validator drops `reportId` from ALLOWED_ATTRIBUTES — it's path-scoped now, not a query filter. Tests: - E2E helpers `createInsight`/`getInsight`/`listInsights`/ `updateInsight`/`deleteInsight` all take `reportId` as the first argument. - New `createFixtureReport()` helper for standalone validation tests that need a parent. - Dropped `testCreateWithoutReport` — reportId is mandatory now. - `testCreateRejectsUnknownReport` now exercises the path-level 404 rather than a body-level check. - `testGet` and `testUpdateMissing` exercise the wrong-reportId-but-valid-insightId case (returns `report_not_found`). - `testList` asserts every result carries the path's reportId, plus a 404 case for a nonexistent parent. - `testCreateForEachEngine` and the standalone create-rejection tests inline-create their own fixture report and clean up after. - `testListSurvivesEmptyDatabase` renamed to `testListSurvivesEmptyReport` and uses a fresh fixture report. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 06:53:54 +00:00
$update = $this->client->call(
Client::METHOD_PATCH,
'/reports/' . ID::unique() . '/insights/' . ID::unique(),
$this->serverHeaders(),
['status' => 'dismissed']
);
$this->assertSame(404, $update['headers']['status-code']);
refactor(insights): nest insights API under reports Insights are children of reports — make the URL hierarchy reflect that. Endpoints: - POST /v1/manager/reports/:reportId/insights (manager Create) - GET /v1/reports/:reportId/insights (List) - GET /v1/reports/:reportId/insights/:insightId (Get) - PATCH /v1/reports/:reportId/insights/:insightId (Update) - DELETE /v1/reports/:reportId/insights/:insightId (Delete) `reportId` moves from optional body field to required path param. All endpoints fetch the report first (404 REPORT_NOT_FOUND if missing or in another project), then verify the insight's `reportInternalId` matches before doing anything else. Side effects: - Event names nested: `reports.[reportId].insights.[insightId].create` etc. Top-level `insights.*` event tree removed from events.php. - Realtime channel parser handles the nested form: a `reports.{rid}` event lights up `reports`, `reports.{rid}` channels; a nested `reports.{rid}.insights.{iid}` event also lights up `reports.{rid}.insights` and `reports.{rid}.insights.{iid}`. - Audit resource paths nested similarly: `report/{request.reportId}/insight/{response.$id}`. - listInsights query validator drops `reportId` from ALLOWED_ATTRIBUTES — it's path-scoped now, not a query filter. Tests: - E2E helpers `createInsight`/`getInsight`/`listInsights`/ `updateInsight`/`deleteInsight` all take `reportId` as the first argument. - New `createFixtureReport()` helper for standalone validation tests that need a parent. - Dropped `testCreateWithoutReport` — reportId is mandatory now. - `testCreateRejectsUnknownReport` now exercises the path-level 404 rather than a body-level check. - `testGet` and `testUpdateMissing` exercise the wrong-reportId-but-valid-insightId case (returns `report_not_found`). - `testList` asserts every result carries the path's reportId, plus a 404 case for a nonexistent parent. - `testCreateForEachEngine` and the standalone create-rejection tests inline-create their own fixture report and clean up after. - `testListSurvivesEmptyDatabase` renamed to `testListSurvivesEmptyReport` and uses a fresh fixture report. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 06:53:54 +00:00
$delete = $this->client->call(
Client::METHOD_DELETE,
'/reports/' . ID::unique() . '/insights/' . ID::unique(),
$this->serverHeaders()
);
$this->assertSame(404, $delete['headers']['status-code']);
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
}
}