TenantAtlas/apps/platform/tests/Feature/TenantConfiguration/Spec415CoverageEvidencePersistenceTest.php
ahmido ca0f54614d feat: add generic content-backed coverage capture (#482)
Automated PR provided by Codex via Gitea API.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #482
2026-06-25 19:55:52 +00:00

77 lines
3.7 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\TenantConfigurationResourceEvidence;
use App\Models\TenantConfigurationResourceType;
use App\Services\Graph\GraphContractRegistry;
use App\Services\TenantConfiguration\CoverageEvidenceWriter;
use App\Services\TenantConfiguration\CoverageResourceUpserter;
use App\Services\TenantConfiguration\CoverageSourceContractResolver;
use App\Services\TenantConfiguration\GenericPayloadNormalizer;
use App\Services\TenantConfiguration\ResourceTypeRegistry;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
it('upserts concrete resources and appends immutable evidence snapshots', function (): void {
app(ResourceTypeRegistry::class)->syncDefaults();
config()->set('graph_contracts.types.assignmentFilter.volatile_fields', ['@odata.etag']);
[$user, $tenant] = createMinimalUserWithTenant(role: 'owner');
$connection = ProviderConnection::factory()->withCredential()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
]);
$run = OperationRun::factory()->withUser($user)->forTenant($tenant)->create([
'type' => OperationRunType::TenantConfigurationCapture->value,
'status' => OperationRunStatus::Running->value,
'outcome' => OperationRunOutcome::Pending->value,
]);
$resourceType = TenantConfigurationResourceType::query()
->where('canonical_type', 'deviceAndAppManagementAssignmentFilter')
->firstOrFail();
$decision = app(CoverageSourceContractResolver::class)->resolve($resourceType);
$normalizer = new GenericPayloadNormalizer;
$firstPayload = ['id' => 'resource-1', 'displayName' => 'Resource', '@odata.etag' => 'one'];
$resource = app(CoverageResourceUpserter::class)->upsert($tenant, $connection, $resourceType, $firstPayload, $decision->sourceMetadata);
$firstNormalized = $normalizer->normalize($firstPayload, ['@odata.etag']);
app(CoverageEvidenceWriter::class)->append(
resource: $resource,
resourceType: $resourceType,
providerConnection: $connection,
operationRun: $run,
decision: $decision,
rawPayload: $firstPayload,
normalizedPayload: $firstNormalized,
payloadHash: $normalizer->payloadHash($firstNormalized),
permissionContext: ['scopes_granted' => []],
);
$secondPayload = ['id' => 'resource-1', 'displayName' => 'Resource updated', '@odata.etag' => 'two'];
$sameResource = app(CoverageResourceUpserter::class)->upsert($tenant, $connection, $resourceType, $secondPayload, $decision->sourceMetadata);
$secondNormalized = $normalizer->normalize($secondPayload, ['@odata.etag']);
$secondEvidence = app(CoverageEvidenceWriter::class)->append(
resource: $sameResource,
resourceType: $resourceType,
providerConnection: $connection,
operationRun: $run,
decision: $decision,
rawPayload: $secondPayload,
normalizedPayload: $secondNormalized,
payloadHash: $normalizer->payloadHash($secondNormalized),
permissionContext: ['scopes_granted' => []],
);
expect($sameResource->getKey())->toBe($resource->getKey())
->and(TenantConfigurationResourceEvidence::query()->where('resource_id', $resource->getKey())->count())->toBe(2)
->and($sameResource->fresh()->latest_evidence_id)->toBe((int) $secondEvidence->getKey())
->and($secondEvidence->operation_run_id)->toBe((int) $run->getKey())
->and($secondEvidence->source_metadata['source_contract_key'])->toBe('assignmentFilter')
->and($secondEvidence->normalized_payload)->not->toHaveKey('@odata.etag');
});