TenantAtlas/apps/platform/tests/Feature/ProviderResources/ProviderResourceBindingPostgresTest.php
Ahmed Darrazi fb2642e941
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m9s
feat(resources): implement provider resource identity binding
Added ProviderResourceBinding model, migrations, policies, and supporting framework for canonical resource identity mapping as defined in Spec 381.
2026-06-15 17:37:06 +02:00

112 lines
4.3 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\ManagedEnvironment;
use App\Models\ProviderResourceBinding;
use App\Support\Resources\ProviderResourceBindingStatus;
use App\Support\Resources\ProviderResourceResolutionMode;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
beforeEach(function (): void {
if (DB::getDriverName() !== 'pgsql') {
$this->markTestSkipped('PostgreSQL-only binding integrity test.');
}
});
it('enforces one active binding per managed environment provider and canonical subject key', function (): void {
$tenant = ManagedEnvironment::factory()->create();
$binding = ProviderResourceBinding::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'provider_key' => 'fake-provider',
'canonical_subject_key' => 'provider-resource:v1:duplicate',
'binding_status' => ProviderResourceBindingStatus::Active->value,
]);
expectPgsqlBindingConstraintViolation(fn () => ProviderResourceBinding::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'provider_key' => 'fake-provider',
'canonical_subject_key' => $binding->canonical_subject_key,
'binding_status' => ProviderResourceBindingStatus::Active->value,
]));
ProviderResourceBinding::factory()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'provider_key' => 'fake-provider',
'canonical_subject_key' => $binding->canonical_subject_key,
'binding_status' => ProviderResourceBindingStatus::Superseded->value,
'ended_at' => now(),
]);
expect(ProviderResourceBinding::query()->where('canonical_subject_key', $binding->canonical_subject_key)->count())->toBe(2);
});
it('enforces managed environment and workspace pair integrity', function (): void {
$tenant = ManagedEnvironment::factory()->create();
$otherTenant = ManagedEnvironment::factory()->create();
$attributes = ProviderResourceBinding::factory()->make([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
])->getAttributes();
$attributes['workspace_id'] = (int) $otherTenant->workspace_id;
expectPgsqlBindingConstraintViolation(fn () => DB::table('provider_resource_bindings')->insert($attributes));
});
it('rejects invalid status and resolution mode values', function (): void {
$tenant = ManagedEnvironment::factory()->create();
$attributes = ProviderResourceBinding::factory()->make([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
])->getAttributes();
$attributes['binding_status'] = 'pending';
expectPgsqlBindingConstraintViolation(fn () => DB::table('provider_resource_bindings')->insert($attributes));
$attributes = ProviderResourceBinding::factory()->make([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
])->getAttributes();
$attributes['resolution_mode'] = 'display_name_match';
expectPgsqlBindingConstraintViolation(fn () => DB::table('provider_resource_bindings')->insert($attributes));
});
it('creates the active lookup partial unique index', function (): void {
$indexDefinition = DB::table('pg_indexes')
->where('schemaname', 'public')
->where('tablename', 'provider_resource_bindings')
->where('indexname', 'provider_resource_bindings_active_unique')
->value('indexdef');
expect((string) $indexDefinition)
->toContain('provider_resource_bindings')
->toContain("WHERE ((binding_status)::text = 'active'::text)");
});
function expectPgsqlBindingConstraintViolation(callable $callback): void
{
$savepoint = 'provider_resource_binding_constraint_check';
$exception = null;
DB::statement("SAVEPOINT {$savepoint}");
try {
$callback();
} catch (QueryException $queryException) {
$exception = $queryException;
} finally {
DB::statement("ROLLBACK TO SAVEPOINT {$savepoint}");
DB::statement("RELEASE SAVEPOINT {$savepoint}");
}
expect($exception)->toBeInstanceOf(QueryException::class);
}