mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
304b0dab35
- Add skipFilters to Reports/Get.php (was the only endpoint still triggering the full N+1 subquery cascade) - Scale CTA batch limit dynamically (insightCount * MAX_CTA_COUNT) instead of fixed APP_LIMIT_SUBQUERY to prevent silent truncation - Revert deleteReport to callback-based pagination so CTAs are not orphaned when a report has more than APP_LIMIT_SUBQUERY insights - Add explicit prefix lengths (700) to _key_project_resource and _key_project_parent_resource indexes to stay under InnoDB 3072-byte limit - Validate CTA service/method against ADVISOR_CTA_SERVICES and ADVISOR_CTA_METHODS enums in the CTAs validator Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
242 lines
6.4 KiB
PHP
242 lines
6.4 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\Advisor\Validator;
|
|
|
|
use Appwrite\Advisor\Validator\CTAs;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class CTAsTest extends TestCase
|
|
{
|
|
public function testRejectsNonArray(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertFalse($validator->isValid('not-an-array'));
|
|
$this->assertFalse($validator->isValid(42));
|
|
$this->assertFalse($validator->isValid(null));
|
|
}
|
|
|
|
public function testAcceptsEmptyArray(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertTrue($validator->isValid([]));
|
|
}
|
|
|
|
public function testAcceptsCompleteEntry(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertTrue($validator->isValid([[
|
|
'label' => 'Create missing index',
|
|
'service' => 'tablesDB',
|
|
'method' => 'createIndex',
|
|
'params' => [
|
|
'databaseId' => 'main',
|
|
'tableId' => 'orders',
|
|
],
|
|
]]));
|
|
}
|
|
|
|
public function testAcceptsEntryWithoutParams(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertTrue($validator->isValid([[
|
|
'label' => 'Create missing index',
|
|
'service' => 'tablesDB',
|
|
'method' => 'createIndex',
|
|
]]));
|
|
}
|
|
|
|
public function testRejectsEntryMissingRequiredKeys(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertFalse($validator->isValid([['label' => 'x']]));
|
|
$this->assertFalse($validator->isValid([['label' => 'x', 'service' => 'tablesDB']]));
|
|
$this->assertFalse($validator->isValid([['label' => 'x', 'method' => 'createIndex']]));
|
|
}
|
|
|
|
public function testRejectsEntryWithEmptyStrings(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
'label' => '',
|
|
'service' => 'tablesDB',
|
|
'method' => 'createIndex',
|
|
]]));
|
|
}
|
|
|
|
public function testRejectsEntryWithNonStringFields(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
'label' => 123,
|
|
'service' => 'tablesDB',
|
|
'method' => 'createIndex',
|
|
]]));
|
|
}
|
|
|
|
public function testRejectsEntryWithScalarParams(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
'label' => 'Create missing index',
|
|
'service' => 'tablesDB',
|
|
'method' => 'createIndex',
|
|
'params' => 'not-a-map',
|
|
]]));
|
|
}
|
|
|
|
public function testReportsArrayType(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertTrue($validator->isArray());
|
|
$this->assertSame($validator::TYPE_ARRAY, $validator->getType());
|
|
}
|
|
|
|
public function testRejectsMoreThanMaxCount(): void
|
|
{
|
|
$validator = new CTAs(maxCount: 3);
|
|
|
|
$entries = [];
|
|
for ($i = 0; $i < 4; $i++) {
|
|
$entries[] = [
|
|
'label' => 'Label ' . $i,
|
|
'service' => 'tablesDB',
|
|
'method' => 'createIndex',
|
|
];
|
|
}
|
|
|
|
$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,
|
|
'service' => 'tablesDB',
|
|
'method' => 'createIndex',
|
|
];
|
|
}
|
|
|
|
$this->assertTrue($validator->isValid($entries));
|
|
}
|
|
|
|
public function testAcceptsObjectParams(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$entry = [
|
|
'label' => 'Create missing index',
|
|
'service' => 'tablesDB',
|
|
'method' => 'createIndex',
|
|
'params' => new \stdClass(),
|
|
];
|
|
|
|
$this->assertTrue($validator->isValid([$entry]));
|
|
}
|
|
|
|
public function testRejectsEntryWithEmptyService(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
'label' => 'Create missing index',
|
|
'service' => '',
|
|
'method' => 'createIndex',
|
|
]]));
|
|
}
|
|
|
|
public function testRejectsEntryWithEmptyMethod(): void
|
|
{
|
|
$validator = new CTAs();
|
|
|
|
$this->assertFalse($validator->isValid([[
|
|
'label' => 'Create missing index',
|
|
'service' => 'tablesDB',
|
|
'method' => '',
|
|
]]));
|
|
}
|
|
|
|
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',
|
|
]]));
|
|
}
|
|
|
|
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,
|
|
'service' => 'tablesDB',
|
|
'method' => 'createIndex',
|
|
];
|
|
}
|
|
|
|
$this->assertTrue($validator->isValid($entries));
|
|
|
|
$entries[] = [
|
|
'label' => 'Label 16',
|
|
'service' => 'tablesDB',
|
|
'method' => 'createIndex',
|
|
];
|
|
|
|
$this->assertFalse($validator->isValid($entries));
|
|
}
|
|
}
|