TenantAtlas/apps/platform/tests/Feature/Jobs/PolicySyncIgnoredRevivalTest.php
ahmido e64bae9cfc feat: cut over tenant core to managed environments (#335)
## Summary
- replace the legacy Tenant and TenantMembership core models with ManagedEnvironment and ManagedEnvironmentMembership
- propagate the managed environment naming and key changes across Filament resources, pages, controllers, jobs, models, and supporting runtime paths
- add feature 279 spec artifacts and focused managed-environment test coverage for model behavior, route binding, panel context, authorization, and legacy guardrails

## Validation
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentAuthorizationTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentPanelContextTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentRouteBindingTest.php tests/Unit/ManagedEnvironment/ManagedEnvironmentContextResolverTest.php tests/Unit/ManagedEnvironment/ManagedEnvironmentModelTest.php`
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`

## Notes
- branch pushed from commit `1123b122`
- browser smoke test file was added but not run in this pass

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #335
2026-05-07 06:38:14 +00:00

167 lines
5.3 KiB
PHP

<?php
use App\Models\Policy;
use App\Models\ManagedEnvironment;
use App\Services\Graph\GraphClientInterface;
use App\Services\Graph\GraphResponse;
use App\Services\Intune\PolicySyncService;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
class FakeGraphClientForSync implements GraphClientInterface
{
/**
* @param array<string, GraphResponse> $responses
*/
public function __construct(private array $responses = []) {}
public function listPolicies(string $policyType, array $options = []): GraphResponse
{
return $this->responses[$policyType] ?? new GraphResponse(true, []);
}
public function getPolicy(string $policyType, string $policyId, array $options = []): GraphResponse
{
return new GraphResponse(true, []);
}
public function getOrganization(array $options = []): GraphResponse
{
return new GraphResponse(true, []);
}
public function applyPolicy(string $policyType, string $policyId, array $payload, array $options = []): GraphResponse
{
return new GraphResponse(true, []);
}
public function getServicePrincipalPermissions(array $options = []): GraphResponse
{
return new GraphResponse(true, []);
}
public function request(string $method, string $path, array $options = []): GraphResponse
{
return new GraphResponse(true, []);
}
}
test('sync preserves local ignore when policies still exist in Intune', function () {
$tenant = ManagedEnvironment::create([
'managed_environment_id' => 'test-tenant',
'name' => 'Test ManagedEnvironment',
'metadata' => [],
'is_current' => true,
]);
ensureDefaultProviderConnection($tenant);
// Create an ignored policy
$policy = Policy::create([
'managed_environment_id' => $tenant->id,
'external_id' => 'policy-123',
'policy_type' => 'deviceConfiguration',
'display_name' => 'Test Policy',
'platform' => 'windows',
'ignored_at' => now(),
]);
expect($policy->ignored_at)->not->toBeNull();
// Mock Graph response with the same policy
$responses = [
'deviceConfiguration' => new GraphResponse(true, [
[
'id' => 'policy-123',
'displayName' => 'Test Policy (Updated)',
'platform' => 'windows',
],
]),
];
app()->instance(GraphClientInterface::class, new FakeGraphClientForSync($responses));
// Sync policies
app(PolicySyncService::class)->syncPolicies($tenant);
// Refresh the policy
$policy->refresh();
// Provider reappearance updates local metadata, but only a user action clears local ignore.
expect($policy->ignored_at)->not->toBeNull();
expect($policy->missing_from_provider_at)->toBeNull();
expect($policy->display_name)->toBe('Test Policy (Updated)');
expect($policy->last_synced_at)->not->toBeNull();
});
test('sync updates ignored policies without reviving them', function () {
$tenant = ManagedEnvironment::create([
'managed_environment_id' => 'test-tenant-2',
'name' => 'Test ManagedEnvironment 2',
'metadata' => [],
'is_current' => true,
]);
ensureDefaultProviderConnection($tenant);
// Create multiple ignored policies
Policy::create([
'managed_environment_id' => $tenant->id,
'external_id' => 'policy-abc',
'policy_type' => 'deviceConfiguration',
'display_name' => 'Old Policy ABC',
'platform' => 'windows',
'ignored_at' => now()->subDay(),
]);
Policy::create([
'managed_environment_id' => $tenant->id,
'external_id' => 'policy-def',
'policy_type' => 'deviceCompliancePolicy',
'display_name' => 'Old Policy DEF',
'platform' => 'android',
'ignored_at' => now()->subDay(),
]);
expect(Policy::active()->count())->toBe(0);
expect(Policy::ignored()->count())->toBe(2);
// Mock Graph response with same policy IDs but potentially different data
$responses = [
'deviceConfiguration' => new GraphResponse(true, [
[
'id' => 'policy-abc',
'displayName' => 'Restored Policy ABC',
'platform' => 'windows',
],
]),
'deviceCompliancePolicy' => new GraphResponse(true, [
[
'id' => 'policy-def',
'displayName' => 'Restored Policy DEF',
'platform' => 'android',
],
]),
];
app()->instance(GraphClientInterface::class, new FakeGraphClientForSync($responses));
// Sync policies
app(PolicySyncService::class)->syncPolicies($tenant);
// Both provider-visible policies remain locally ignored until explicitly restored.
expect(Policy::active()->count())->toBe(0);
expect(Policy::ignored()->count())->toBe(2);
$policyAbc = Policy::where('external_id', 'policy-abc')->first();
expect($policyAbc->display_name)->toBe('Restored Policy ABC');
expect($policyAbc->ignored_at)->not->toBeNull();
expect($policyAbc->missing_from_provider_at)->toBeNull();
$policyDef = Policy::where('external_id', 'policy-def')->first();
expect($policyDef->display_name)->toBe('Restored Policy DEF');
expect($policyDef->ignored_at)->not->toBeNull();
expect($policyDef->missing_from_provider_at)->toBeNull();
});