fix: provision and clean up alert records

This commit is contained in:
Jake Barnby
2026-05-16 22:35:28 +12:00
parent 730b1cb723
commit d76ef18b57
5 changed files with 161 additions and 1 deletions
+8 -1
View File
@@ -1261,9 +1261,16 @@ $platformCollections = [
'$id' => ID::custom('_key_projectInternalId'),
'type' => Database::INDEX_KEY,
'attributes' => ['projectInternalId'],
'lengths' => [Database::LENGTH_KEY],
'lengths' => [0],
'orders' => [Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_project'),
'type' => Database::INDEX_KEY,
'attributes' => ['projectId', 'projectInternalId'],
'lengths' => [Database::LENGTH_KEY, 0],
'orders' => [Database::ORDER_ASC, Database::ORDER_ASC],
],
[
'$id' => ID::custom('_key_project_resource'),
'type' => Database::INDEX_KEY,
+4
View File
@@ -88,6 +88,10 @@ class V24 extends Migration
$collections = $this->collections[$collectionType];
if ($collectionType === 'console') {
$this->createCollection('alerts');
}
foreach ($collections as $collection) {
$id = $collection['$id'];
+11
View File
@@ -732,6 +732,17 @@ class Deletes extends Action
Console::error('Failed to delete schedules: ' . $th->getMessage());
}
// Delete Alerts
try {
$this->deleteByGroup('alerts', [
Query::equal('projectId', [$projectId]),
Query::equal('projectInternalId', [$projectInternalId]),
Query::orderAsc()
], $dbForPlatform);
} catch (Throwable $th) {
Console::error('Failed to delete alerts: ' . $th->getMessage());
}
// Delete Advisor insights
try {
$this->deleteByGroup('insights', [
@@ -3,7 +3,14 @@
namespace Tests\Unit\Migration;
use Appwrite\Migration\Migration;
use Appwrite\Migration\Version\V24;
use PHPUnit\Framework\TestCase;
use Utopia\Cache\Adapter\None as NoCache;
use Utopia\Cache\Cache;
use Utopia\Database\Adapter\Memory;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
class MigrationVersionsTest extends TestCase
{
@@ -24,4 +31,44 @@ class MigrationVersionsTest extends TestCase
$this->assertArrayHasKey(APP_VERSION_STABLE, Migration::$versions);
}
}
public function testV24CreatesAlertsCollectionForConsoleProject(): void
{
require_once __DIR__ . '/../../../app/init.php';
$authorization = new Authorization();
$database = new Database(new Memory(), new Cache(new NoCache()));
$database
->setAuthorization($authorization)
->setDatabase('migrationV24')
->setNamespace('migration_' . \uniqid());
$database->create();
$migration = new V24();
$migration->setProject(
new Document(['$id' => 'console', '$sequence' => 'console']),
$database,
$database,
$authorization,
);
$migrateCollections = new \ReflectionMethod($migration, 'migrateCollections');
\ob_start();
try {
$migrateCollections->invoke($migration);
} finally {
\ob_end_clean();
}
$collection = $database->getCollection('alerts');
$this->assertFalse($collection->isEmpty());
$attributes = [];
foreach ($collection->getAttribute('attributes', []) as $attribute) {
$id = $attribute instanceof Document ? $attribute->getAttribute('$id') : ($attribute['$id'] ?? '');
$attributes[$id] = $attribute;
}
$this->assertArrayHasKey('resourceInternalId', $attributes);
$this->assertArrayHasKey('parentResourceInternalId', $attributes);
}
}
@@ -0,0 +1,91 @@
<?php
namespace Tests\Unit\Platform\Workers;
use Appwrite\Certificates\Adapter as CertificatesAdapter;
use Appwrite\Platform\Workers\Deletes;
use PHPUnit\Framework\TestCase;
use Utopia\Cache\Adapter\None as NoCache;
use Utopia\Cache\Cache;
use Utopia\Database\Adapter\Memory;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Storage\Device;
require_once __DIR__ . '/../../../../app/init.php';
class DeletesTest extends TestCase
{
public function testProjectDeleteScopesAlertsByProjectIdAndProjectInternalId(): void
{
$database = new Database(new Memory(), new Cache(new NoCache()));
$project = new Document([
'$id' => 'project-1',
'$sequence' => 'project-internal-1',
'database' => 'mysql://localhost/appwrite',
]);
$worker = new class () extends Deletes {
/**
* @var array<string, array<Query>>
*/
public array $groups = [];
public function runProjectDelete(
Database $database,
Document $project,
callable $getProjectDB,
callable $getDatabasesDB,
Device $device,
CertificatesAdapter $certificates,
): void {
$this->deleteProject(
$database,
$getProjectDB,
$getDatabasesDB,
$device,
$device,
$device,
$device,
$device,
$certificates,
$project,
);
}
protected function deleteByGroup(string $collection, array $queries, Database $database, ?callable $callback = null): void
{
$this->groups[$collection] = $queries;
}
};
$getProjectDB = static fn () => throw new \RuntimeException('stop');
$getDatabasesDB = static fn () => $database;
try {
$worker->runProjectDelete(
$database,
$project,
$getProjectDB,
$getDatabasesDB,
$this->createStub(Device::class),
$this->createStub(CertificatesAdapter::class),
);
} catch (\RuntimeException $exception) {
$this->assertSame('stop', $exception->getMessage());
}
$this->assertArrayHasKey('alerts', $worker->groups);
$queries = $worker->groups['alerts'];
$this->assertSame(Query::TYPE_EQUAL, $queries[0]->getMethod());
$this->assertSame('projectId', $queries[0]->getAttribute());
$this->assertSame(['project-1'], $queries[0]->getValues());
$this->assertSame(Query::TYPE_EQUAL, $queries[1]->getMethod());
$this->assertSame('projectInternalId', $queries[1]->getAttribute());
$this->assertSame(['project-internal-1'], $queries[1]->getValues());
$this->assertSame(Query::TYPE_ORDER_ASC, $queries[2]->getMethod());
}
}