$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 revives ignored policies when they exist in Intune', function () { $tenant = Tenant::create([ 'tenant_id' => 'test-tenant', 'name' => 'Test Tenant', 'metadata' => [], 'is_current' => true, ]); // Create an ignored policy $policy = Policy::create([ 'tenant_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(); // Policy should no longer be ignored expect($policy->ignored_at)->toBeNull(); expect($policy->display_name)->toBe('Test Policy (Updated)'); expect($policy->last_synced_at)->not->toBeNull(); }); test('sync creates new policies even if ignored ones exist with same external_id', function () { $tenant = Tenant::create([ 'tenant_id' => 'test-tenant-2', 'name' => 'Test Tenant 2', 'metadata' => [], 'is_current' => true, ]); // Create multiple ignored policies Policy::create([ 'tenant_id' => $tenant->id, 'external_id' => 'policy-abc', 'policy_type' => 'deviceConfiguration', 'display_name' => 'Old Policy ABC', 'platform' => 'windows', 'ignored_at' => now()->subDay(), ]); Policy::create([ 'tenant_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); // All policies should now be active expect(Policy::active()->count())->toBe(2); expect(Policy::ignored()->count())->toBe(0); $policyAbc = Policy::where('external_id', 'policy-abc')->first(); expect($policyAbc->display_name)->toBe('Restored Policy ABC'); expect($policyAbc->ignored_at)->toBeNull(); $policyDef = Policy::where('external_id', 'policy-def')->first(); expect($policyDef->display_name)->toBe('Restored Policy DEF'); expect($policyDef->ignored_at)->toBeNull(); });