282 lines
9.3 KiB
PHP
282 lines
9.3 KiB
PHP
<?php
|
|
|
|
use App\Models\BackupItem;
|
|
use App\Models\BackupSet;
|
|
use App\Models\Tenant;
|
|
use App\Services\Graph\GraphClientInterface;
|
|
use App\Services\Graph\GraphResponse;
|
|
use App\Services\Intune\FoundationMappingService;
|
|
use App\Services\Intune\FoundationSnapshotService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Mockery\MockInterface;
|
|
use Tests\TestCase;
|
|
|
|
uses(TestCase::class, RefreshDatabase::class);
|
|
|
|
class FoundationMappingGraphClient implements GraphClientInterface
|
|
{
|
|
public array $requests = [];
|
|
|
|
/**
|
|
* @param array<int, GraphResponse> $responses
|
|
*/
|
|
public function __construct(private array $responses = []) {}
|
|
|
|
public function listPolicies(string $policyType, array $options = []): GraphResponse
|
|
{
|
|
return new GraphResponse(success: true, data: []);
|
|
}
|
|
|
|
public function getPolicy(string $policyType, string $policyId, array $options = []): GraphResponse
|
|
{
|
|
return new GraphResponse(success: true, data: []);
|
|
}
|
|
|
|
public function getOrganization(array $options = []): GraphResponse
|
|
{
|
|
return new GraphResponse(success: true, data: []);
|
|
}
|
|
|
|
public function applyPolicy(string $policyType, string $policyId, array $payload, array $options = []): GraphResponse
|
|
{
|
|
return new GraphResponse(success: true, data: []);
|
|
}
|
|
|
|
public function getServicePrincipalPermissions(array $options = []): GraphResponse
|
|
{
|
|
return new GraphResponse(success: true, data: []);
|
|
}
|
|
|
|
public function request(string $method, string $path, array $options = []): GraphResponse
|
|
{
|
|
$this->requests[] = [
|
|
'method' => $method,
|
|
'path' => $path,
|
|
'options' => $options,
|
|
];
|
|
|
|
return array_shift($this->responses) ?? new GraphResponse(success: true, data: []);
|
|
}
|
|
}
|
|
|
|
it('maps existing foundations by display name', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
$backupSet = BackupSet::factory()->for($tenant)->create();
|
|
$item = BackupItem::factory()
|
|
->for($tenant)
|
|
->for($backupSet)
|
|
->state([
|
|
'policy_id' => null,
|
|
'policy_identifier' => 'filter-1',
|
|
'policy_type' => 'assignmentFilter',
|
|
'platform' => 'all',
|
|
'payload' => [
|
|
'id' => 'filter-1',
|
|
'displayName' => 'Filter One',
|
|
],
|
|
'metadata' => [
|
|
'displayName' => 'Filter One',
|
|
],
|
|
])
|
|
->create();
|
|
|
|
$this->mock(FoundationSnapshotService::class, function (MockInterface $mock) {
|
|
$mock->shouldReceive('fetchAll')
|
|
->once()
|
|
->andReturn([
|
|
'items' => [
|
|
[
|
|
'source_id' => 'filter-2',
|
|
'display_name' => 'Filter One',
|
|
'payload' => [],
|
|
'metadata' => [],
|
|
],
|
|
],
|
|
'failures' => [],
|
|
]);
|
|
});
|
|
|
|
$client = new FoundationMappingGraphClient;
|
|
app()->instance(GraphClientInterface::class, $client);
|
|
|
|
$service = app(FoundationMappingService::class);
|
|
$result = $service->map($tenant, collect([$item]), false);
|
|
|
|
expect($result['failed'])->toBe(0);
|
|
expect($result['skipped'])->toBe(0);
|
|
expect($result['mapping'])->toBe(['filter-1' => 'filter-2']);
|
|
expect($result['entries'])->toHaveCount(1);
|
|
expect($result['entries'][0]['decision'])->toBe('mapped_existing');
|
|
expect($result['entries'][0]['targetId'])->toBe('filter-2');
|
|
expect($result['entries'][0]['sourceName'])->toBe('Filter One');
|
|
});
|
|
|
|
it('creates missing foundations when executing', function () {
|
|
config()->set('graph_contracts.types.assignmentFilter', [
|
|
'resource' => 'deviceManagement/assignmentFilters',
|
|
'create_method' => 'POST',
|
|
'update_strip_keys' => ['isBuiltIn'],
|
|
]);
|
|
|
|
$tenant = Tenant::factory()->create([
|
|
'tenant_id' => 'tenant-1',
|
|
'app_client_id' => 'client-1',
|
|
'app_client_secret' => 'secret-1',
|
|
]);
|
|
$backupSet = BackupSet::factory()->for($tenant)->create();
|
|
$item = BackupItem::factory()
|
|
->for($tenant)
|
|
->for($backupSet)
|
|
->state([
|
|
'policy_id' => null,
|
|
'policy_identifier' => 'filter-1',
|
|
'policy_type' => 'assignmentFilter',
|
|
'platform' => 'all',
|
|
'payload' => [
|
|
'id' => 'filter-1',
|
|
'@odata.type' => '#microsoft.graph.deviceAndAppManagementAssignmentFilter',
|
|
'displayName' => 'Filter One',
|
|
'isBuiltIn' => false,
|
|
],
|
|
'metadata' => [
|
|
'displayName' => 'Filter One',
|
|
],
|
|
])
|
|
->create();
|
|
|
|
$this->mock(FoundationSnapshotService::class, function (MockInterface $mock) {
|
|
$mock->shouldReceive('fetchAll')
|
|
->once()
|
|
->andReturn([
|
|
'items' => [
|
|
[
|
|
'source_id' => 'filter-2',
|
|
'display_name' => 'Filter One',
|
|
'payload' => [],
|
|
'metadata' => [],
|
|
],
|
|
[
|
|
'source_id' => 'filter-3',
|
|
'display_name' => 'Filter One',
|
|
'payload' => [],
|
|
'metadata' => [],
|
|
],
|
|
],
|
|
'failures' => [],
|
|
]);
|
|
});
|
|
|
|
$client = new FoundationMappingGraphClient([
|
|
new GraphResponse(true, [
|
|
'id' => 'filter-99',
|
|
'displayName' => 'Filter One (Copy)',
|
|
]),
|
|
]);
|
|
app()->instance(GraphClientInterface::class, $client);
|
|
|
|
$service = app(FoundationMappingService::class);
|
|
$result = $service->map($tenant, collect([$item]), true);
|
|
|
|
expect($result['mapping'])->toBe(['filter-1' => 'filter-99']);
|
|
expect($result['entries'][0]['decision'])->toBe('created_copy');
|
|
expect($result['entries'][0]['targetName'])->toBe('Filter One (Copy)');
|
|
expect($client->requests)->toHaveCount(1);
|
|
expect($client->requests[0]['method'])->toBe('POST');
|
|
expect($client->requests[0]['path'])->toBe('deviceManagement/assignmentFilters');
|
|
|
|
$payload = $client->requests[0]['options']['json'];
|
|
expect($payload['displayName'])->toBe('Filter One (Copy)');
|
|
expect($payload)->not->toHaveKey('id');
|
|
expect($payload)->not->toHaveKey('@odata.type');
|
|
expect($payload)->not->toHaveKey('isBuiltIn');
|
|
});
|
|
|
|
it('skips built-in scope tags', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
$backupSet = BackupSet::factory()->for($tenant)->create();
|
|
$item = BackupItem::factory()
|
|
->for($tenant)
|
|
->for($backupSet)
|
|
->state([
|
|
'policy_id' => null,
|
|
'policy_identifier' => '0',
|
|
'policy_type' => 'roleScopeTag',
|
|
'platform' => 'all',
|
|
'payload' => [
|
|
'id' => '0',
|
|
'displayName' => 'Default',
|
|
'isBuiltIn' => true,
|
|
],
|
|
'metadata' => [
|
|
'displayName' => 'Default',
|
|
],
|
|
])
|
|
->create();
|
|
|
|
$this->mock(FoundationSnapshotService::class, function (MockInterface $mock) {
|
|
$mock->shouldReceive('fetchAll')
|
|
->once()
|
|
->andReturn([
|
|
'items' => [],
|
|
'failures' => [],
|
|
]);
|
|
});
|
|
|
|
$client = new FoundationMappingGraphClient;
|
|
app()->instance(GraphClientInterface::class, $client);
|
|
|
|
$service = app(FoundationMappingService::class);
|
|
$result = $service->map($tenant, collect([$item]), false);
|
|
|
|
expect($result['skipped'])->toBe(1);
|
|
expect($result['entries'][0]['decision'])->toBe('skipped');
|
|
expect($result['entries'][0]['reason'])->toBe('Built-in scope tag cannot be created.');
|
|
});
|
|
|
|
it('marks failures when foundation listing fails', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
$backupSet = BackupSet::factory()->for($tenant)->create();
|
|
$item = BackupItem::factory()
|
|
->for($tenant)
|
|
->for($backupSet)
|
|
->state([
|
|
'policy_id' => null,
|
|
'policy_identifier' => 'filter-1',
|
|
'policy_type' => 'assignmentFilter',
|
|
'platform' => 'all',
|
|
'payload' => [
|
|
'id' => 'filter-1',
|
|
'displayName' => 'Filter One',
|
|
],
|
|
'metadata' => [
|
|
'displayName' => 'Filter One',
|
|
],
|
|
])
|
|
->create();
|
|
|
|
$this->mock(FoundationSnapshotService::class, function (MockInterface $mock) {
|
|
$mock->shouldReceive('fetchAll')
|
|
->once()
|
|
->andReturn([
|
|
'items' => [],
|
|
'failures' => [
|
|
[
|
|
'foundation_type' => 'assignmentFilter',
|
|
'reason' => 'Graph failure',
|
|
'status' => 500,
|
|
],
|
|
],
|
|
]);
|
|
});
|
|
|
|
$client = new FoundationMappingGraphClient;
|
|
app()->instance(GraphClientInterface::class, $client);
|
|
|
|
$service = app(FoundationMappingService::class);
|
|
$result = $service->map($tenant, collect([$item]), false);
|
|
|
|
expect($result['failed'])->toBe(1);
|
|
expect($result['entries'][0]['decision'])->toBe('failed');
|
|
expect($result['entries'][0]['reason'])->toBe('Graph failure');
|
|
});
|