TenantAtlas/apps/platform/tests/Unit/CompliancePolicyNormalizerTest.php
ahmido ce0615a9c1 Spec 182: relocate Laravel platform to apps/platform (#213)
## Summary
- move the Laravel application into `apps/platform` and keep the repository root for orchestration, docs, and tooling
- update the local command model, Sail/Docker wiring, runtime paths, and ignore rules around the new platform location
- add relocation quickstart/contracts plus focused smoke coverage for bootstrap, command model, routes, and runtime behavior

## Validation
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/PlatformRelocation`
- integrated browser smoke validated `/up`, `/`, `/admin`, `/admin/choose-workspace`, and tenant route semantics for `200`, `403`, and `404`

## Remaining Rollout Checks
- validate Dokploy build context and working-directory assumptions against the new `apps/platform` layout
- confirm web, queue, and scheduler processes all start from the expected working directory in staging/production
- verify no legacy volume mounts or asset-publish paths still point at the old root-level `public/` or `storage/` locations

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #213
2026-04-08 08:40:47 +00:00

158 lines
6.8 KiB
PHP

<?php
use App\Services\Intune\CompliancePolicyNormalizer;
it('groups compliance policy fields into structured blocks', function () {
$normalizer = app(CompliancePolicyNormalizer::class);
$snapshot = [
'@odata.type' => '#microsoft.graph.windows10CompliancePolicy',
'passwordRequired' => true,
'passwordMinimumLength' => 8,
'defenderEnabled' => true,
'bitLockerEnabled' => false,
'osMinimumVersion' => '10.0.19045',
'activeFirewallRequired' => true,
'scheduledActionsForRule' => [
[
'ruleName' => 'Default rule',
'scheduledActionConfigurations' => [
['actionType' => 'notification'],
],
],
],
'scheduledActionsForRule@odata.context' => 'https://graph.microsoft.com/beta/$metadata#deviceManagement/deviceCompliancePolicies',
'customSetting' => 'Custom value',
];
$normalized = $normalizer->normalize($snapshot, 'deviceCompliancePolicy', 'windows');
$settings = collect($normalized['settings']);
$passwordBlock = $settings->firstWhere('title', 'Password & Access');
expect($passwordBlock)->not->toBeNull();
expect(collect($passwordBlock['rows'])->pluck('label')->all())
->toContain('Password required', 'Password minimum length');
$additionalBlock = $settings->firstWhere('title', 'Additional Settings');
expect($additionalBlock)->not->toBeNull();
expect(collect($additionalBlock['rows'])->pluck('label')->all())
->toContain('Custom Setting');
expect(collect($additionalBlock['rows'])->pluck('label')->all())
->not->toContain('Scheduled Actions For Rule');
expect(collect($additionalBlock['rows'])->pluck('label')->all())
->not->toContain('Scheduled Actions For Rule@Odata.context');
expect($settings->pluck('title')->all())->not->toContain('General');
});
it('flattens compliance noncompliance actions into a canonical diff signal', function () {
$normalizer = app(CompliancePolicyNormalizer::class);
$snapshot = [
'@odata.type' => '#microsoft.graph.windows10CompliancePolicy',
'passwordRequired' => true,
'scheduledActionsForRule' => [
[
'ruleName' => null,
'scheduledActionConfigurations' => [
[
'actionType' => 'block',
'gracePeriodHours' => 240,
'notificationTemplateId' => '00000000-0000-0000-0000-000000000000',
],
[
'actionType' => 'notification',
'gracePeriodHours' => 48,
'notificationTemplateId' => 'template-123',
],
[
'actionType' => 'retire',
'gracePeriodHours' => 2664,
'notificationTemplateId' => 'template-retire',
],
],
],
],
'scheduledActionsForRule@odata.context' => 'https://graph.microsoft.com/beta/$metadata#deviceManagement/deviceCompliancePolicies',
];
$flat = $normalizer->flattenForDiff($snapshot, 'deviceCompliancePolicy', 'windows');
expect($flat)->toHaveKey('Password & Access > Password required');
expect($flat['Password & Access > Password required'])->toBeTrue();
expect($flat)->toHaveKey('Actions for noncompliance > Mark device noncompliant > Grace period');
expect($flat['Actions for noncompliance > Mark device noncompliant > Grace period'])->toBe('10 days (240 hours)');
expect($flat)->toHaveKey('Actions for noncompliance > Mark device noncompliant > Notification template ID');
expect($flat['Actions for noncompliance > Mark device noncompliant > Notification template ID'])->toBeNull();
expect($flat)->toHaveKey('Actions for noncompliance > Send notification > Grace period');
expect($flat['Actions for noncompliance > Send notification > Grace period'])->toBe('2 days (48 hours)');
expect($flat['Actions for noncompliance > Send notification > Notification template ID'])->toBe('template-123');
expect($flat)->toHaveKey('Actions for noncompliance > Add device to retire list > Grace period');
expect($flat['Actions for noncompliance > Add device to retire list > Grace period'])->toBe('111 days (2664 hours)');
expect($flat['Actions for noncompliance > Add device to retire list > Notification template ID'])->toBe('template-retire');
expect(array_keys($flat))->not->toContain('scheduledActionsForRule');
expect(array_keys($flat))->not->toContain('scheduledActionsForRule@odata.context');
});
it('ignores noncompliance action ids and ordering when flattening for diff', function () {
$normalizer = app(CompliancePolicyNormalizer::class);
$firstSnapshot = [
'@odata.type' => '#microsoft.graph.windows10CompliancePolicy',
'scheduledActionsForRule' => [
[
'ruleName' => null,
'scheduledActionConfigurations' => [
[
'id' => 'config-a',
'actionType' => 'notification',
'gracePeriodHours' => 48,
'notificationTemplateId' => 'template-b',
],
[
'id' => 'config-b',
'actionType' => 'notification',
'gracePeriodHours' => 24,
'notificationTemplateId' => 'template-a',
],
],
],
],
];
$secondSnapshot = [
'@odata.type' => '#microsoft.graph.windows10CompliancePolicy',
'scheduledActionsForRule' => [
[
'ruleName' => null,
'scheduledActionConfigurations' => [
[
'id' => 'config-z',
'actionType' => 'notification',
'gracePeriodHours' => 24,
'notificationTemplateId' => 'template-a',
],
[
'id' => 'config-y',
'actionType' => 'notification',
'gracePeriodHours' => 48,
'notificationTemplateId' => 'template-b',
],
],
],
],
];
$firstFlat = $normalizer->flattenForDiff($firstSnapshot, 'deviceCompliancePolicy', 'windows');
$secondFlat = $normalizer->flattenForDiff($secondSnapshot, 'deviceCompliancePolicy', 'windows');
expect($firstFlat)->toBe($secondFlat);
expect($firstFlat)->toHaveKey('Actions for noncompliance > Send notification #1 > Grace period');
expect($firstFlat)->toHaveKey('Actions for noncompliance > Send notification #2 > Grace period');
});