mock(GraphClientInterface::class, function ($mock): void { $mock->shouldReceive('listPolicies')->never(); $mock->shouldReceive('getPolicy')->never(); $mock->shouldReceive('getOrganization')->never(); $mock->shouldReceive('applyPolicy')->never(); $mock->shouldReceive('getServicePrincipalPermissions')->never(); $mock->shouldReceive('request')->never(); }); [$user, $tenant] = createUserWithTenant(role: 'operator'); $this->actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); $connection = ProviderConnection::factory()->create([ 'tenant_id' => $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => fake()->uuid(), ]); $component = Livewire::test(EditProviderConnection::class, ['record' => $connection->getRouteKey()]); $component->callAction('inventory_sync'); $component->callAction('inventory_sync'); $opRun = OperationRun::query() ->where('tenant_id', $tenant->getKey()) ->where('type', 'inventory.sync') ->latest('id') ->first(); expect($opRun)->not->toBeNull(); expect($opRun?->context)->toMatchArray([ 'provider' => 'microsoft', 'module' => 'inventory', 'provider_connection_id' => (int) $connection->getKey(), 'target_scope' => [ 'entra_tenant_id' => $connection->entra_tenant_id, ], ]); expect(OperationRun::query() ->where('tenant_id', $tenant->getKey()) ->where('type', 'inventory.sync') ->count())->toBe(1); Queue::assertPushed(ProviderInventorySyncJob::class, 1); }); it('dedupes compliance snapshot runs and does not call Graph during start', function (): void { Queue::fake(); $this->mock(GraphClientInterface::class, function ($mock): void { $mock->shouldReceive('listPolicies')->never(); $mock->shouldReceive('getPolicy')->never(); $mock->shouldReceive('getOrganization')->never(); $mock->shouldReceive('applyPolicy')->never(); $mock->shouldReceive('getServicePrincipalPermissions')->never(); $mock->shouldReceive('request')->never(); }); [$user, $tenant] = createUserWithTenant(role: 'operator'); $this->actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); $connection = ProviderConnection::factory()->create([ 'tenant_id' => $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => fake()->uuid(), ]); $component = Livewire::test(EditProviderConnection::class, ['record' => $connection->getRouteKey()]); $component->callAction('compliance_snapshot'); $component->callAction('compliance_snapshot'); $opRun = OperationRun::query() ->where('tenant_id', $tenant->getKey()) ->where('type', 'compliance.snapshot') ->latest('id') ->first(); expect($opRun)->not->toBeNull(); expect($opRun?->context)->toMatchArray([ 'provider' => 'microsoft', 'module' => 'compliance', 'provider_connection_id' => (int) $connection->getKey(), 'target_scope' => [ 'entra_tenant_id' => $connection->entra_tenant_id, ], ]); expect(OperationRun::query() ->where('tenant_id', $tenant->getKey()) ->where('type', 'compliance.snapshot') ->count())->toBe(1); Queue::assertPushed(ProviderComplianceSnapshotJob::class, 1); }); it('blocks different provider operations for the same scope as scope busy', function (): void { Queue::fake(); [$user, $tenant] = createUserWithTenant(role: 'operator'); $this->actingAs($user); $tenant->makeCurrent(); Filament::setTenant($tenant, true); $connection = ProviderConnection::factory()->create([ 'tenant_id' => $tenant->getKey(), 'provider' => 'microsoft', 'entra_tenant_id' => fake()->uuid(), ]); $component = Livewire::test(EditProviderConnection::class, ['record' => $connection->getRouteKey()]); $component->callAction('inventory_sync'); $component->callAction('compliance_snapshot'); $inventoryRun = OperationRun::query() ->where('tenant_id', $tenant->getKey()) ->where('type', 'inventory.sync') ->latest('id') ->first(); expect($inventoryRun)->not->toBeNull(); expect(OperationRun::query() ->where('tenant_id', $tenant->getKey()) ->where('type', 'compliance.snapshot') ->count())->toBe(0); Queue::assertPushed(ProviderInventorySyncJob::class, 1); Queue::assertPushed(ProviderComplianceSnapshotJob::class, 0); $notifications = session('filament.notifications', []); expect($notifications)->not->toBeEmpty(); expect(collect($notifications)->last()['actions'][0]['url'] ?? null) ->toBe(OperationRunLinks::view($inventoryRun, $tenant)); });