create([ 'tenant_id' => $tenant->getKey(), 'selection_key' => 'groups-v1:all', 'status' => EntraGroupSyncRun::STATUS_PENDING, 'initiator_user_id' => $user->getKey(), ]); EntraGroup::factory()->create([ 'tenant_id' => $tenant->getKey(), 'entra_id' => '11111111-1111-1111-1111-111111111111', 'display_name' => 'Old Name', 'last_seen_at' => now('UTC')->subDays(10), ]); $mock = \Mockery::mock(GraphClientInterface::class); $mock->shouldReceive('request') ->twice() ->andReturn( new GraphResponse(success: true, data: [ 'value' => [ [ 'id' => '11111111-1111-1111-1111-111111111111', 'displayName' => 'New Name', 'groupTypes' => ['Unified'], 'securityEnabled' => false, 'mailEnabled' => true, ], ], '@odata.nextLink' => 'https://graph.microsoft.com/v1.0/groups?$skiptoken=abc', ], status: 200), new GraphResponse(success: true, data: [ 'value' => [ [ 'id' => '22222222-2222-2222-2222-222222222222', 'displayName' => 'Second Group', 'groupTypes' => [], 'securityEnabled' => true, 'mailEnabled' => false, ], ], ], status: 200), ); app()->instance(GraphClientInterface::class, $mock); $job = new EntraGroupSyncJob( tenantId: (int) $tenant->getKey(), selectionKey: 'groups-v1:all', slotKey: null, runId: (int) $run->getKey(), ); $job->handle(app(EntraGroupSyncService::class), app(AuditLogger::class)); $run->refresh(); expect($run->status)->toBe(EntraGroupSyncRun::STATUS_SUCCEEDED) ->and($run->pages_fetched)->toBe(2) ->and($run->items_observed_count)->toBe(2) ->and($run->items_upserted_count)->toBe(2) ->and($run->error_count)->toBe(0) ->and($run->finished_at)->not->toBeNull(); expect(EntraGroup::query()->where('tenant_id', $tenant->getKey())->count())->toBe(2); $updated = EntraGroup::query() ->where('tenant_id', $tenant->getKey()) ->where('entra_id', '11111111-1111-1111-1111-111111111111') ->first(); expect($updated)->not->toBeNull() ->and($updated->display_name)->toBe('New Name') ->and($updated->mail_enabled)->toBeTrue(); });