## Summary
This PR completes spec 422 exchange teams comparable renderable pack with comparable diffing, renderable summary builders, and comprehensive test updates.
## Commit
- 4c1e14c6 feat: complete spec 422 exchange teams comparable renderable pack
Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #489
101 lines
4.3 KiB
PHP
101 lines
4.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Services\TenantConfiguration\ExchangeTeamsCoverageComparator;
|
|
|
|
it('Spec422 treats Exchange and Teams volatile-only differences as unchanged', function (string $canonicalType, array $payload): void {
|
|
$result = app(ExchangeTeamsCoverageComparator::class)->compare(
|
|
$canonicalType,
|
|
[...$payload, 'modifiedDateTime' => '2026-06-28T10:00:00Z'],
|
|
[...$payload, 'modifiedDateTime' => '2026-06-28T11:00:00Z'],
|
|
);
|
|
|
|
expect($result['changed'])->toBeFalse()
|
|
->and($result['classification'])->toBe('unchanged')
|
|
->and(collect($result['changes'])->pluck('classification'))->toContain('ignored_volatile');
|
|
})->with([
|
|
'transport rule' => ['transportRule', ['DisplayName' => 'Rule', 'Enabled' => true]],
|
|
'meeting policy' => ['meetingPolicy', ['DisplayName' => 'Meeting', 'AllowCloudRecording' => true]],
|
|
]);
|
|
|
|
it('Spec422 detects material Exchange and Teams changes with bounded importance', function (string $canonicalType, array $before, array $after, string $field, string $importance, string $classification = 'changed'): void {
|
|
$result = app(ExchangeTeamsCoverageComparator::class)->compare($canonicalType, $before, $after);
|
|
$change = collect($result['changes'])->firstWhere('field', $field);
|
|
|
|
expect($result['changed'])->toBeTrue()
|
|
->and($result['classification'])->toBe('changed')
|
|
->and($change)->not->toBeNull()
|
|
->and($change['classification'])->toBe($classification)
|
|
->and($change['importance'])->toBe($importance);
|
|
})->with([
|
|
'transport enabled' => [
|
|
'transportRule',
|
|
['DisplayName' => 'Rule', 'Enabled' => true],
|
|
['DisplayName' => 'Rule', 'Enabled' => false],
|
|
'enabled_state',
|
|
'critical',
|
|
],
|
|
'accepted domain default' => [
|
|
'acceptedDomain',
|
|
['DomainName' => 'contoso.com', 'IsDefault' => false],
|
|
['DomainName' => 'contoso.com', 'IsDefault' => true],
|
|
'is_default',
|
|
'critical',
|
|
],
|
|
'app blocked list' => [
|
|
'appPermissionPolicy',
|
|
['DisplayName' => 'Policy', 'BlockAppList' => []],
|
|
['DisplayName' => 'Policy', 'BlockAppList' => [['DisplayName' => 'Consumer App', 'AppId' => 'consumer-app']]],
|
|
'blocked_apps',
|
|
'critical',
|
|
'added',
|
|
],
|
|
'meeting transcription' => [
|
|
'meetingPolicy',
|
|
['DisplayName' => 'Meeting', 'AllowTranscription' => false],
|
|
['DisplayName' => 'Meeting', 'AllowTranscription' => true],
|
|
'recording_transcription.allow_transcription',
|
|
'critical',
|
|
],
|
|
]);
|
|
|
|
it('Spec422 keeps array ordering stable and handles null or empty values explicitly', function (): void {
|
|
$ordered = app(ExchangeTeamsCoverageComparator::class)->compare('appPermissionPolicy', [
|
|
'DisplayName' => 'Policy',
|
|
'AllowAppList' => [
|
|
['DisplayName' => 'Planner', 'AppId' => 'planner-app'],
|
|
['DisplayName' => 'Bookings', 'AppId' => 'bookings-app'],
|
|
],
|
|
], [
|
|
'DisplayName' => 'Policy',
|
|
'AllowAppList' => [
|
|
['DisplayName' => 'Bookings', 'AppId' => 'bookings-app'],
|
|
['DisplayName' => 'Planner', 'AppId' => 'planner-app'],
|
|
],
|
|
]);
|
|
$added = app(ExchangeTeamsCoverageComparator::class)->compare('meetingPolicy', [
|
|
'DisplayName' => 'Meeting',
|
|
'AllowCloudRecording' => null,
|
|
], [
|
|
'DisplayName' => 'Meeting',
|
|
'AllowCloudRecording' => true,
|
|
]);
|
|
|
|
expect($ordered['changed'])->toBeFalse()
|
|
->and($added['changed'])->toBeTrue()
|
|
->and(collect($added['changes'])->firstWhere('field', 'recording_transcription.allow_cloud_recording')['classification'])->toBe('added');
|
|
});
|
|
|
|
it('Spec422 records redacted and unsupported Exchange/Teams fields as non-material diagnostics', function (): void {
|
|
$result = app(ExchangeTeamsCoverageComparator::class)->compare(
|
|
'transportRule',
|
|
['DisplayName' => 'Rule', 'Enabled' => true],
|
|
['DisplayName' => 'Rule', 'Enabled' => true, 'clientSecret' => 'spec422-comparator-secret'],
|
|
);
|
|
|
|
expect($result['changed'])->toBeFalse()
|
|
->and(collect($result['changes'])->pluck('classification'))->toContain('redacted', 'unsupported_field')
|
|
->and(json_encode($result, JSON_THROW_ON_ERROR))->not->toContain('spec422-comparator-secret');
|
|
});
|