What Changed Removed per-file uses(TestCase::class ...) bindings in Unit tests to avoid Pest v4 “folder already uses the test case” discovery failure (kept RefreshDatabase where needed). Updated the backup scheduling job test to pass the newly required BulkOperationService when manually calling RunBackupScheduleJob::handle(). Where Unit (bulk cleanup across 56 files) RunBackupScheduleJobTest.php Verification ./vendor/bin/sail test → 443 passed, 5 skipped Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local> Reviewed-on: #45
178 lines
5.2 KiB
PHP
178 lines
5.2 KiB
PHP
<?php
|
|
|
|
use App\Services\Graph\GraphException;
|
|
use App\Services\Graph\GraphResponse;
|
|
use App\Services\Graph\GroupResolver;
|
|
use App\Services\Graph\MicrosoftGraphClient;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
uses(RefreshDatabase::class);
|
|
beforeEach(function () {
|
|
Cache::flush();
|
|
$this->graphClient = Mockery::mock(MicrosoftGraphClient::class);
|
|
$this->resolver = new GroupResolver($this->graphClient);
|
|
});
|
|
|
|
test('resolves all groups', function () {
|
|
$tenantId = 'tenant-123';
|
|
$groupIds = ['group-1', 'group-2', 'group-3'];
|
|
$graphData = [
|
|
'value' => [
|
|
['id' => 'group-1', 'displayName' => 'All Users'],
|
|
['id' => 'group-2', 'displayName' => 'HR Team'],
|
|
['id' => 'group-3', 'displayName' => 'Contractors'],
|
|
],
|
|
];
|
|
|
|
$response = new GraphResponse(
|
|
success: true,
|
|
data: $graphData
|
|
);
|
|
|
|
$this->graphClient
|
|
->shouldReceive('request')
|
|
->once()
|
|
->with('POST', '/directoryObjects/getByIds', [
|
|
'tenant' => $tenantId,
|
|
'json' => [
|
|
'ids' => $groupIds,
|
|
'types' => ['group'],
|
|
],
|
|
])
|
|
->andReturn($response);
|
|
|
|
$result = $this->resolver->resolveGroupIds($groupIds, $tenantId);
|
|
|
|
expect($result)->toHaveKey('group-1')
|
|
->and($result['group-1'])->toBe([
|
|
'id' => 'group-1',
|
|
'displayName' => 'All Users',
|
|
'orphaned' => false,
|
|
])
|
|
->and($result)->toHaveKey('group-2')
|
|
->and($result['group-2']['orphaned'])->toBeFalse()
|
|
->and($result)->toHaveKey('group-3')
|
|
->and($result['group-3']['orphaned'])->toBeFalse();
|
|
});
|
|
|
|
test('handles orphaned ids', function () {
|
|
$tenantId = 'tenant-123';
|
|
$groupIds = ['group-1', 'group-2', 'group-3'];
|
|
$graphData = [
|
|
'value' => [
|
|
['id' => 'group-1', 'displayName' => 'All Users'],
|
|
// group-2 and group-3 are missing (deleted)
|
|
],
|
|
];
|
|
|
|
$response = new GraphResponse(
|
|
success: true,
|
|
data: $graphData
|
|
);
|
|
|
|
$this->graphClient
|
|
->shouldReceive('request')
|
|
->once()
|
|
->andReturn($response);
|
|
|
|
$result = $this->resolver->resolveGroupIds($groupIds, $tenantId);
|
|
|
|
expect($result)->toHaveKey('group-1')
|
|
->and($result['group-1']['orphaned'])->toBeFalse()
|
|
->and($result)->toHaveKey('group-2')
|
|
->and($result['group-2'])->toBe([
|
|
'id' => 'group-2',
|
|
'displayName' => null,
|
|
'orphaned' => true,
|
|
])
|
|
->and($result)->toHaveKey('group-3')
|
|
->and($result['group-3']['orphaned'])->toBeTrue();
|
|
});
|
|
|
|
test('caches results', function () {
|
|
$tenantId = 'tenant-123';
|
|
$groupIds = ['group-1', 'group-2'];
|
|
$graphData = [
|
|
'value' => [
|
|
['id' => 'group-1', 'displayName' => 'All Users'],
|
|
['id' => 'group-2', 'displayName' => 'HR Team'],
|
|
],
|
|
];
|
|
|
|
$response = new GraphResponse(
|
|
success: true,
|
|
data: $graphData
|
|
);
|
|
|
|
// First call - should hit Graph API
|
|
$this->graphClient
|
|
->shouldReceive('request')
|
|
->once()
|
|
->andReturn($response);
|
|
|
|
$result1 = $this->resolver->resolveGroupIds($groupIds, $tenantId);
|
|
|
|
// Second call - should use cache (no Graph API call)
|
|
$result2 = $this->resolver->resolveGroupIds($groupIds, $tenantId);
|
|
|
|
expect($result1)->toBe($result2)
|
|
->and($result1)->toHaveCount(2);
|
|
});
|
|
|
|
test('returns empty array for empty input', function () {
|
|
$result = $this->resolver->resolveGroupIds([], 'tenant-123');
|
|
|
|
expect($result)->toBe([]);
|
|
});
|
|
|
|
test('handles graph exception gracefully', function () {
|
|
$tenantId = 'tenant-123';
|
|
$groupIds = ['group-1', 'group-2'];
|
|
|
|
$this->graphClient
|
|
->shouldReceive('request')
|
|
->once()
|
|
->andThrow(new GraphException('Graph API error', 500, ['request_id' => 'request-id-123']));
|
|
|
|
$result = $this->resolver->resolveGroupIds($groupIds, $tenantId);
|
|
|
|
// All groups should be marked as orphaned on failure
|
|
expect($result)->toHaveKey('group-1')
|
|
->and($result['group-1']['orphaned'])->toBeTrue()
|
|
->and($result['group-1']['displayName'])->toBeNull()
|
|
->and($result)->toHaveKey('group-2')
|
|
->and($result['group-2']['orphaned'])->toBeTrue();
|
|
});
|
|
|
|
test('cache key is consistent regardless of array order', function () {
|
|
$tenantId = 'tenant-123';
|
|
$groupIds1 = ['group-1', 'group-2', 'group-3'];
|
|
$groupIds2 = ['group-3', 'group-1', 'group-2']; // Different order
|
|
$graphData = [
|
|
'value' => [
|
|
['id' => 'group-1', 'displayName' => 'All Users'],
|
|
['id' => 'group-2', 'displayName' => 'HR Team'],
|
|
['id' => 'group-3', 'displayName' => 'Contractors'],
|
|
],
|
|
];
|
|
|
|
$response = new GraphResponse(
|
|
success: true,
|
|
data: $graphData
|
|
);
|
|
|
|
// First call with groupIds1
|
|
$this->graphClient
|
|
->shouldReceive('request')
|
|
->once()
|
|
->andReturn($response);
|
|
|
|
$result1 = $this->resolver->resolveGroupIds($groupIds1, $tenantId);
|
|
|
|
// Second call with groupIds2 (different order) - should use cache
|
|
$result2 = $this->resolver->resolveGroupIds($groupIds2, $tenantId);
|
|
|
|
expect($result1)->toBe($result2);
|
|
});
|