TenantAtlas/tests/Unit/MicrosoftGraphClientListPoliciesSelectTest.php

161 lines
5.3 KiB
PHP

<?php
declare(strict_types=1);
uses(Tests\TestCase::class);
use App\Services\Graph\GraphContractRegistry;
use App\Services\Graph\GraphLogger;
use App\Services\Graph\MicrosoftGraphClient;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
it('includes contract select fields when listing policies', function () {
Http::fake([
'graph.microsoft.com/*' => Http::response(['value' => []], 200),
]);
$logger = mock(GraphLogger::class);
$logger->shouldReceive('logRequest')->zeroOrMoreTimes()->andReturnNull();
$logger->shouldReceive('logResponse')->zeroOrMoreTimes()->andReturnNull();
$client = new MicrosoftGraphClient(
logger: $logger,
contracts: app(GraphContractRegistry::class),
);
$client->listPolicies('endpointSecurityPolicy', [
'access_token' => 'test-token',
]);
$client->listPolicies('securityBaselinePolicy', [
'access_token' => 'test-token',
]);
$client->listPolicies('settingsCatalogPolicy', [
'access_token' => 'test-token',
]);
Http::assertSent(function (Request $request) {
$url = $request->url();
if (! str_contains($url, '/deviceManagement/configurationPolicies')) {
return false;
}
parse_str((string) parse_url($url, PHP_URL_QUERY), $query);
expect($query)->toHaveKey('$select');
$select = (string) $query['$select'];
expect($select)->toContain('technologies')
->and($select)->toContain('templateReference')
->and($select)->toContain('name')
->and($select)->not->toContain('@odata.type');
expect($select)->not->toContain('displayName');
expect($select)->not->toContain('version');
return true;
});
});
it('retries list policies without $select on select/expand parsing errors', function () {
Http::fake([
'graph.microsoft.com/*' => Http::sequence()
->push([
'error' => [
'code' => 'BadRequest',
'message' => "Parsing OData Select and Expand failed: Could not find a property named 'version' on type 'microsoft.graph.deviceManagementConfigurationPolicy'.",
],
], 400)
->push([
'error' => [
'code' => 'BadRequest',
'message' => "Parsing OData Select and Expand failed: Could not find a property named 'version' on type 'microsoft.graph.deviceManagementConfigurationPolicy'.",
],
], 400)
->push(['value' => [['id' => 'policy-1', 'name' => 'Policy One']]], 200),
]);
$logger = mock(GraphLogger::class);
$logger->shouldReceive('logRequest')->zeroOrMoreTimes()->andReturnNull();
$logger->shouldReceive('logResponse')->zeroOrMoreTimes()->andReturnNull();
$client = new MicrosoftGraphClient(
logger: $logger,
contracts: app(GraphContractRegistry::class),
);
$response = $client->listPolicies('settingsCatalogPolicy', [
'access_token' => 'test-token',
]);
expect($response->successful())->toBeTrue();
expect($response->data)->toHaveCount(1);
expect($response->warnings)->toContain('Capability fallback applied: removed $select for compatibility.');
$recorded = Http::recorded();
expect($recorded)->toHaveCount(3);
[$firstRequest] = $recorded[0];
[$secondRequest] = $recorded[1];
[$thirdRequest] = $recorded[2];
parse_str((string) parse_url($firstRequest->url(), PHP_URL_QUERY), $firstQuery);
parse_str((string) parse_url($secondRequest->url(), PHP_URL_QUERY), $secondQuery);
parse_str((string) parse_url($thirdRequest->url(), PHP_URL_QUERY), $thirdQuery);
expect($firstQuery)->toHaveKey('$select');
expect($secondQuery)->toHaveKey('$select');
expect($thirdQuery)->not->toHaveKey('$select');
});
it('paginates list policies when nextLink is present', function () {
$nextLink = 'https://graph.microsoft.com/beta/deviceManagement/configurationPolicies?$skiptoken=page2';
Http::fake([
'graph.microsoft.com/*' => Http::sequence()
->push([
'value' => [
['id' => 'policy-1', 'name' => 'Policy One'],
],
'@odata.nextLink' => $nextLink,
], 200)
->push([
'value' => [
['id' => 'policy-2', 'name' => 'Policy Two'],
],
], 200),
]);
$logger = mock(GraphLogger::class);
$logger->shouldReceive('logRequest')->zeroOrMoreTimes()->andReturnNull();
$logger->shouldReceive('logResponse')->zeroOrMoreTimes()->andReturnNull();
$client = new MicrosoftGraphClient(
logger: $logger,
contracts: app(GraphContractRegistry::class),
);
$response = $client->listPolicies('settingsCatalogPolicy', [
'access_token' => 'test-token',
]);
expect($response->successful())->toBeTrue();
expect($response->data)->toHaveCount(2);
expect(collect($response->data)->pluck('id')->all())->toMatchArray(['policy-1', 'policy-2']);
$recorded = Http::recorded();
expect($recorded)->toHaveCount(2);
[$firstRequest] = $recorded[0];
[$secondRequest] = $recorded[1];
expect($firstRequest->url())->toContain('/deviceManagement/configurationPolicies');
expect($secondRequest->url())->toBe($nextLink);
});