TenantAtlas/apps/platform/tests/Unit/Support/Baselines/BaselineSubjectResolutionQueryTest.php
ahmido 39298f27f2 feat(ui): implement baseline subject resolution ui (#455)
Added `BaselineSubjectResolution` page and supporting logic to visualize missing identities, ambiguous matches, and skipped coverages as defined in Spec 384. Replaces legacy compare warnings with an actionable, deterministic UI surface.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #455
2026-06-16 23:36:38 +00:00

169 lines
7.2 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Baselines\BaselineSubjectResolutionQuery;
use App\Support\Baselines\SubjectClass;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\Resources\ResourceIdentity;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\Feature\Baselines\Support\BaselineSubjectResolutionFixtures;
uses(RefreshDatabase::class);
it('derives actionable rows and candidates from persisted compare semantics and inventory identities', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
[$profile, $snapshot] = seedActiveBaselineForTenant($tenant);
$leftIdentity = ResourceIdentity::providerResource('fake-provider', 'policy', 'candidate-left');
$rightIdentity = ResourceIdentity::providerResource('fake-provider', 'policy', 'candidate-right');
BaselineSubjectResolutionFixtures::inventoryCandidate($tenant, $leftIdentity, 'Duplicate policy');
BaselineSubjectResolutionFixtures::inventoryCandidate($tenant, $rightIdentity, 'Duplicate policy');
$leftDescriptor = BaselineSubjectResolutionFixtures::providerDescriptor($leftIdentity, 'Duplicate policy');
$rightDescriptor = BaselineSubjectResolutionFixtures::providerDescriptor($rightIdentity, 'Duplicate policy');
$run = seedBaselineCompareRun(
tenant: $tenant,
profile: $profile,
snapshot: $snapshot,
compareContext: [
'result_semantics' => [
'version' => 1,
'subject_outcomes' => [
BaselineSubjectResolutionFixtures::semanticOutcome([
'reason' => 'unresolved_duplicate_candidates',
'actionability' => 'binding_required',
'readiness_impact' => 'customer_blocker',
'subject' => [
'subject_domain' => 'baseline',
'subject_class' => SubjectClass::PolicyBacked->value,
'subject_type_key' => 'deviceConfiguration',
'subject_key' => 'legacy-display-key',
'display_label' => 'Duplicate policy',
'candidate_descriptors' => [
$leftDescriptor->toArray(),
$rightDescriptor->toArray(),
],
],
]),
BaselineSubjectResolutionFixtures::semanticOutcome([
'reason' => 'verified_no_drift',
'actionability' => 'none',
'readiness_impact' => 'no_impact',
'subject' => [
'subject_type_key' => 'deviceConfiguration',
'subject_key' => 'resolved-subject',
'display_label' => 'Resolved subject',
],
]),
],
],
],
status: OperationRunStatus::Completed->value,
outcome: OperationRunOutcome::PartiallySucceeded->value,
);
$rows = app(BaselineSubjectResolutionQuery::class)->rows($tenant, [
'operation_run_id' => (int) $run->getKey(),
]);
expect($rows)->toHaveCount(1)
->and($rows[0]['reason'])->toBe('unresolved_duplicate_candidates')
->and($rows[0]['actionability'])->toBe('binding_required')
->and($rows[0]['candidate_count'])->toBe(2)
->and($rows[0]['decision_identity'])->toBeNull()
->and(collect($rows[0]['candidates'])->pluck('identity.provider_resource_id')->all())
->toContain('candidate-left', 'candidate-right');
expect(app(BaselineSubjectResolutionQuery::class)->rows($tenant, [
'operation_run_id' => (int) $run->getKey(),
'actionability' => 'binding_required',
'readiness_impact' => 'customer_blocker',
'reason' => 'unresolved_duplicate_candidates',
'resource_type' => 'deviceConfiguration',
'candidates' => 'yes',
'active_binding' => 'no',
]))->toHaveCount(1);
$resolvedRows = app(BaselineSubjectResolutionQuery::class)->rows($tenant, [
'operation_run_id' => (int) $run->getKey(),
'include_resolved' => true,
]);
expect($resolvedRows)->toHaveCount(2);
});
it('does not derive bindable candidates from display label matches alone', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
[$profile, $snapshot] = seedActiveBaselineForTenant($tenant);
BaselineSubjectResolutionFixtures::inventoryCandidate(
$tenant,
ResourceIdentity::providerResource('fake-provider', 'policy', 'candidate-left'),
'Duplicate policy',
);
BaselineSubjectResolutionFixtures::inventoryCandidate(
$tenant,
ResourceIdentity::providerResource('fake-provider', 'policy', 'candidate-right'),
'Duplicate policy',
);
$run = seedBaselineCompareRun(
tenant: $tenant,
profile: $profile,
snapshot: $snapshot,
compareContext: [
'result_semantics' => [
'version' => 1,
'subject_outcomes' => [
BaselineSubjectResolutionFixtures::semanticOutcome([
'reason' => 'unresolved_duplicate_candidates',
'actionability' => 'binding_required',
'readiness_impact' => 'customer_blocker',
'subject' => [
'subject_domain' => 'baseline',
'subject_class' => SubjectClass::PolicyBacked->value,
'subject_type_key' => 'deviceConfiguration',
'subject_key' => 'legacy-display-key',
'display_label' => 'Duplicate policy',
],
]),
],
],
],
status: OperationRunStatus::Completed->value,
outcome: OperationRunOutcome::PartiallySucceeded->value,
);
$rows = app(BaselineSubjectResolutionQuery::class)->rows($tenant, [
'operation_run_id' => (int) $run->getKey(),
]);
expect($rows)->toHaveCount(1)
->and($rows[0]['candidate_count'])->toBe(0)
->and($rows[0]['candidates'])->toBe([]);
});
it('does not treat legacy evidence-gap payloads as authoritative subject decisions', function (): void {
[$user, $tenant] = createUserWithTenant(role: 'owner');
[$profile, $snapshot] = seedActiveBaselineForTenant($tenant);
$run = seedBaselineCompareRun($tenant, $profile, $snapshot, [
'evidence_gaps' => [
'count' => 1,
'by_reason' => ['unresolved_duplicate_candidates' => 1],
'subjects' => [[
'policy_type' => 'deviceConfiguration',
'subject_key' => 'legacy-only',
'reason_code' => 'unresolved_duplicate_candidates',
]],
],
], outcome: OperationRunOutcome::PartiallySucceeded->value);
$query = app(BaselineSubjectResolutionQuery::class);
expect($query->rows($tenant, ['operation_run_id' => (int) $run->getKey()]))->toBe([])
->and($query->summary($tenant, (int) $run->getKey())['legacy_payload_only'])->toBeTrue();
});