From 6d131fff6acc82eec1d6df57d76010321d55eb9c Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Thu, 10 Sep 2026 16:45:26 +0200 Subject: [PATCH 1/2] feat: Add SystemReport api to OCP Allow other apps to add additional section to the system report. Signed-off-by: Carl Schwan --- lib/composer/composer/autoload_classmap.php | 5 + lib/composer/composer/autoload_static.php | 5 + .../Bootstrap/RegistrationContext.php | 26 +++++ lib/private/Server.php | 3 + .../SystemReport/SystemReportManager.php | 45 +++++++++ .../Bootstrap/IRegistrationContext.php | 9 ++ .../SystemReport/ISystemReportManager.php | 26 +++++ .../SystemReport/ISystemReportSection.php | 41 ++++++++ .../SystemReport/SystemReportDetail.php | 47 +++++++++ .../SystemReport/SystemReportDetailFormat.php | 24 +++++ .../SystemReport/SystemReportManagerTest.php | 97 +++++++++++++++++++ 11 files changed, 328 insertions(+) create mode 100644 lib/private/SystemReport/SystemReportManager.php create mode 100644 lib/public/SystemReport/ISystemReportManager.php create mode 100644 lib/public/SystemReport/ISystemReportSection.php create mode 100644 lib/public/SystemReport/SystemReportDetail.php create mode 100644 lib/public/SystemReport/SystemReportDetailFormat.php create mode 100644 tests/lib/SystemReport/SystemReportManagerTest.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 26372e14d14ae..8354e46e14a29 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -982,6 +982,10 @@ 'OCP\\Support\\Subscription\\IRegistry' => $baseDir . '/lib/public/Support/Subscription/IRegistry.php', 'OCP\\Support\\Subscription\\ISubscription' => $baseDir . '/lib/public/Support/Subscription/ISubscription.php', 'OCP\\Support\\Subscription\\ISupportedApps' => $baseDir . '/lib/public/Support/Subscription/ISupportedApps.php', + 'OCP\\SystemReport\\ISystemReportManager' => $baseDir . '/lib/public/SystemReport/ISystemReportManager.php', + 'OCP\\SystemReport\\ISystemReportSection' => $baseDir . '/lib/public/SystemReport/ISystemReportSection.php', + 'OCP\\SystemReport\\SystemReportDetail' => $baseDir . '/lib/public/SystemReport/SystemReportDetail.php', + 'OCP\\SystemReport\\SystemReportDetailFormat' => $baseDir . '/lib/public/SystemReport/SystemReportDetailFormat.php', 'OCP\\SystemTag\\Events\\AbstractTagEvent' => $baseDir . '/lib/public/SystemTag/Events/AbstractTagEvent.php', 'OCP\\SystemTag\\Events\\TagCreatedEvent' => $baseDir . '/lib/public/SystemTag/Events/TagCreatedEvent.php', 'OCP\\SystemTag\\Events\\TagDeletedEvent' => $baseDir . '/lib/public/SystemTag/Events/TagDeletedEvent.php', @@ -2376,6 +2380,7 @@ 'OC\\Support\\Subscription\\Assertion' => $baseDir . '/lib/private/Support/Subscription/Assertion.php', 'OC\\Support\\Subscription\\Registry' => $baseDir . '/lib/private/Support/Subscription/Registry.php', 'OC\\SystemConfig' => $baseDir . '/lib/private/SystemConfig.php', + 'OC\\SystemReport\\SystemReportManager' => $baseDir . '/lib/private/SystemReport/SystemReportManager.php', 'OC\\SystemTag\\ManagerFactory' => $baseDir . '/lib/private/SystemTag/ManagerFactory.php', 'OC\\SystemTag\\SystemTag' => $baseDir . '/lib/private/SystemTag/SystemTag.php', 'OC\\SystemTag\\SystemTagManager' => $baseDir . '/lib/private/SystemTag/SystemTagManager.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index f796225eb4d7e..1600f52f771bb 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -1023,6 +1023,10 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Support\\Subscription\\IRegistry' => __DIR__ . '/../../..' . '/lib/public/Support/Subscription/IRegistry.php', 'OCP\\Support\\Subscription\\ISubscription' => __DIR__ . '/../../..' . '/lib/public/Support/Subscription/ISubscription.php', 'OCP\\Support\\Subscription\\ISupportedApps' => __DIR__ . '/../../..' . '/lib/public/Support/Subscription/ISupportedApps.php', + 'OCP\\SystemReport\\ISystemReportManager' => __DIR__ . '/../../..' . '/lib/public/SystemReport/ISystemReportManager.php', + 'OCP\\SystemReport\\ISystemReportSection' => __DIR__ . '/../../..' . '/lib/public/SystemReport/ISystemReportSection.php', + 'OCP\\SystemReport\\SystemReportDetail' => __DIR__ . '/../../..' . '/lib/public/SystemReport/SystemReportDetail.php', + 'OCP\\SystemReport\\SystemReportDetailFormat' => __DIR__ . '/../../..' . '/lib/public/SystemReport/SystemReportDetailFormat.php', 'OCP\\SystemTag\\Events\\AbstractTagEvent' => __DIR__ . '/../../..' . '/lib/public/SystemTag/Events/AbstractTagEvent.php', 'OCP\\SystemTag\\Events\\TagCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/SystemTag/Events/TagCreatedEvent.php', 'OCP\\SystemTag\\Events\\TagDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/SystemTag/Events/TagDeletedEvent.php', @@ -2417,6 +2421,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Support\\Subscription\\Assertion' => __DIR__ . '/../../..' . '/lib/private/Support/Subscription/Assertion.php', 'OC\\Support\\Subscription\\Registry' => __DIR__ . '/../../..' . '/lib/private/Support/Subscription/Registry.php', 'OC\\SystemConfig' => __DIR__ . '/../../..' . '/lib/private/SystemConfig.php', + 'OC\\SystemReport\\SystemReportManager' => __DIR__ . '/../../..' . '/lib/private/SystemReport/SystemReportManager.php', 'OC\\SystemTag\\ManagerFactory' => __DIR__ . '/../../..' . '/lib/private/SystemTag/ManagerFactory.php', 'OC\\SystemTag\\SystemTag' => __DIR__ . '/../../..' . '/lib/private/SystemTag/SystemTag.php', 'OC\\SystemTag\\SystemTagManager' => __DIR__ . '/../../..' . '/lib/private/SystemTag/SystemTagManager.php', diff --git a/lib/private/AppFramework/Bootstrap/RegistrationContext.php b/lib/private/AppFramework/Bootstrap/RegistrationContext.php index 9b1e1efab24b9..184f1014572af 100644 --- a/lib/private/AppFramework/Bootstrap/RegistrationContext.php +++ b/lib/private/AppFramework/Bootstrap/RegistrationContext.php @@ -41,6 +41,7 @@ use OCP\Share\IPublicShareTemplateProvider; use OCP\SpeechToText\ISpeechToTextProvider; use OCP\Support\CrashReport\IReporter; +use OCP\SystemReport\ISystemReportSection; use OCP\Talk\ITalkBackend; use OCP\TaskProcessing\ITaskType; use OCP\Teams\ITeamResourceProvider; @@ -144,6 +145,9 @@ class RegistrationContext { /** @var ServiceRegistration[] */ private array $setupChecks = []; + /** @var ServiceRegistration[] */ + private array $systemReportSections = []; + /** @var PreviewProviderRegistration[] */ private array $previewProviders = []; @@ -448,6 +452,14 @@ public function registerSetupCheck(string $setupCheckClass): void { ); } + #[\Override] + public function registerSystemReportSection(string $sectionClass): void { + $this->context->registerSystemReportSection( + $this->appId, + $sectionClass + ); + } + #[\Override] public function registerDeclarativeSettings(string $declarativeSettingsClass): void { $this->context->registerDeclarativeSettings( @@ -678,6 +690,13 @@ public function registerSetupCheck(string $appId, string $setupCheckClass): void $this->setupChecks[] = new ServiceRegistration($appId, $setupCheckClass); } + /** + * @psalm-param class-string $sectionClass + */ + public function registerSystemReportSection(string $appId, string $sectionClass): void { + $this->systemReportSections[] = new ServiceRegistration($appId, $sectionClass); + } + /** * @psalm-param class-string $declarativeSettingsClass */ @@ -1055,6 +1074,13 @@ public function getSetupChecks(): array { return $this->setupChecks; } + /** + * @return ServiceRegistration[] + */ + public function getSystemReportSections(): array { + return $this->systemReportSections; + } + /** * @return ServiceRegistration[] */ diff --git a/lib/private/Server.php b/lib/private/Server.php index c1aae75d9fb48..c8675a55308fd 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -145,6 +145,7 @@ use OC\Snowflake\SnowflakeGenerator; use OC\SpeechToText\SpeechToTextManager; use OC\Support\Subscription\Assertion; +use OC\SystemReport\SystemReportManager; use OC\SystemTag\ManagerFactory as SystemTagManagerFactory; use OC\Talk\Broker; use OC\Teams\TeamManager; @@ -280,6 +281,7 @@ use OCP\Snowflake\ISnowflakeGenerator; use OCP\SpeechToText\ISpeechToTextManager; use OCP\Support\Subscription\IAssertion; +use OCP\SystemReport\ISystemReportManager; use OCP\SystemTag\ISystemTagManager; use OCP\SystemTag\ISystemTagManagerFactory; use OCP\SystemTag\ISystemTagObjectMapper; @@ -1132,6 +1134,7 @@ function () use ($c) { $this->registerDeprecatedAlias(IOCMProvider::class, OCMProvider::class); $this->registerAlias(ISetupCheckManager::class, SetupCheckManager::class); + $this->registerAlias(ISystemReportManager::class, SystemReportManager::class); $this->registerAlias(IProfileManager::class, ProfileManager::class); $this->registerAlias(IAvailabilityCoordinator::class, AvailabilityCoordinator::class); $this->registerAlias(IDeclarativeManager::class, DeclarativeManager::class); diff --git a/lib/private/SystemReport/SystemReportManager.php b/lib/private/SystemReport/SystemReportManager.php new file mode 100644 index 0000000000000..f87f35d0c75d1 --- /dev/null +++ b/lib/private/SystemReport/SystemReportManager.php @@ -0,0 +1,45 @@ +coordinator->getRegistrationContext()->getSystemReportSections(); + foreach ($registrations as $registration) { + $class = $registration->getService(); + try { + /** @var ISystemReportSection $section */ + $section = Server::get($class); + // Trigger detail collection here so a failing section is skipped + // instead of surfacing later when the report is rendered. + $section->getDetails(); + } catch (\Throwable $t) { + $this->logger->error('Exception while collecting system report section ' . $class . ': ' . $t->getMessage(), ['exception' => $t]); + continue; + } + $sections[] = $section; + } + return $sections; + } +} diff --git a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php index 31ba916358393..7efea8bcc9c45 100644 --- a/lib/public/AppFramework/Bootstrap/IRegistrationContext.php +++ b/lib/public/AppFramework/Bootstrap/IRegistrationContext.php @@ -388,6 +388,15 @@ public function registerPublicShareTemplateProvider(string $class): void; */ public function registerSetupCheck(string $setupCheckClass): void; + /** + * Register an implementation of \OCP\SystemReport\ISystemReportSection that + * will contribute a section to the system report + * + * @param class-string<\OCP\SystemReport\ISystemReportSection> $sectionClass + * @since 36.0.0 + */ + public function registerSystemReportSection(string $sectionClass): void; + /** * Register an implementation of \OCP\Settings\IDeclarativeSettings that * will handle the implementation of declarative settings diff --git a/lib/public/SystemReport/ISystemReportManager.php b/lib/public/SystemReport/ISystemReportManager.php new file mode 100644 index 0000000000000..e34780b97b747 --- /dev/null +++ b/lib/public/SystemReport/ISystemReportManager.php @@ -0,0 +1,26 @@ +title; + } + + /** @since 36.0.0 */ + public function getContent(): string { + return $this->content; + } + + /** @since 36.0.0 */ + public function getFormat(): SystemReportDetailFormat { + return $this->format; + } +} diff --git a/lib/public/SystemReport/SystemReportDetailFormat.php b/lib/public/SystemReport/SystemReportDetailFormat.php new file mode 100644 index 0000000000000..263330bd8d823 --- /dev/null +++ b/lib/public/SystemReport/SystemReportDetailFormat.php @@ -0,0 +1,24 @@ +coordinator = $this->createMock(Coordinator::class); + $this->logger = $this->createMock(LoggerInterface::class); + $this->manager = new SystemReportManager( + $this->coordinator, + $this->logger, + ); + } + + private function withRegisteredSections(array $registrations): void { + $context = $this->createMock(RegistrationContext::class); + $context->expects(self::atLeastOnce()) + ->method('getSystemReportSections') + ->willReturn($registrations); + + $this->coordinator->expects(self::atLeastOnce()) + ->method('getRegistrationContext') + ->willReturn($context); + } + + public function testGetSectionsReturnsNoneWhenNoneRegistered(): void { + $this->withRegisteredSections([]); + + $this->assertSame([], $this->manager->getSections()); + } + + public function testGetSectionsResolvesAndReturnsRegisteredSections(): void { + $section = $this->createMock(ISystemReportSection::class); + $section->expects(self::once()) + ->method('getDetails') + ->willReturn([]); + + \OC::$server->registerService('OCA\\Testing\\SystemReport\\FakeSection', fn () => $section, false); + + $this->withRegisteredSections([ + new ServiceRegistration('testing', 'OCA\\Testing\\SystemReport\\FakeSection'), + ]); + + $this->assertSame([$section], $this->manager->getSections()); + } + + public function testGetSectionsSkipsSectionThrowingDuringCollection(): void { + $section = $this->createMock(ISystemReportSection::class); + $section->method('getDetails') + ->willThrowException(new \RuntimeException('boom')); + + \OC::$server->registerService('OCA\\Testing\\SystemReport\\ThrowingSection', fn () => $section, false); + + $this->withRegisteredSections([ + new ServiceRegistration('testing', 'OCA\\Testing\\SystemReport\\ThrowingSection'), + ]); + + $this->logger->expects(self::once()) + ->method('error'); + + $this->assertSame([], $this->manager->getSections()); + } + + public function testGetSectionsSkipsUnresolvableClass(): void { + $this->withRegisteredSections([ + new ServiceRegistration('testing', 'OCA\\Testing\\SystemReport\\DoesNotExist'), + ]); + + $this->logger->expects(self::once()) + ->method('error'); + + $this->assertSame([], $this->manager->getSections()); + } +} From c245f180e7fd87a0e9f0bf28fcece95ede250913 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Fri, 11 Sep 2026 15:09:10 +0200 Subject: [PATCH 2/2] refactor(support): Move ldap report generation to user_ldap Signed-off-by: Carl Schwan --- .../composer/composer/autoload_classmap.php | 1 + .../composer/composer/autoload_static.php | 1 + apps/user_ldap/lib/AppInfo/Application.php | 2 + .../lib/Support/SystemReportSection.php | 86 +++++++++++++++++++ build/rector-strict.php | 3 + .../SystemReport/SystemReportManager.php | 18 ++-- .../SystemReport/SystemReportDetail.php | 8 +- psalm-strict.xml | 3 + .../SystemReport/SystemReportManagerTest.php | 32 +++++-- 9 files changed, 138 insertions(+), 16 deletions(-) create mode 100644 apps/user_ldap/lib/Support/SystemReportSection.php diff --git a/apps/user_ldap/composer/composer/autoload_classmap.php b/apps/user_ldap/composer/composer/autoload_classmap.php index a1743773f49eb..4b9858dbc984e 100644 --- a/apps/user_ldap/composer/composer/autoload_classmap.php +++ b/apps/user_ldap/composer/composer/autoload_classmap.php @@ -88,6 +88,7 @@ 'OCA\\User_LDAP\\Settings\\Section' => $baseDir . '/../lib/Settings/Section.php', 'OCA\\User_LDAP\\SetupChecks\\LdapConnection' => $baseDir . '/../lib/SetupChecks/LdapConnection.php', 'OCA\\User_LDAP\\SetupChecks\\LdapInvalidUuids' => $baseDir . '/../lib/SetupChecks/LdapInvalidUuids.php', + 'OCA\\User_LDAP\\Support\\SystemReportSection' => $baseDir . '/../lib/Support/SystemReportSection.php', 'OCA\\User_LDAP\\UserPluginManager' => $baseDir . '/../lib/UserPluginManager.php', 'OCA\\User_LDAP\\User\\DeletedUsersIndex' => $baseDir . '/../lib/User/DeletedUsersIndex.php', 'OCA\\User_LDAP\\User\\Manager' => $baseDir . '/../lib/User/Manager.php', diff --git a/apps/user_ldap/composer/composer/autoload_static.php b/apps/user_ldap/composer/composer/autoload_static.php index af3ddfbdf020a..07ea6c3d53583 100644 --- a/apps/user_ldap/composer/composer/autoload_static.php +++ b/apps/user_ldap/composer/composer/autoload_static.php @@ -103,6 +103,7 @@ class ComposerStaticInitUser_LDAP 'OCA\\User_LDAP\\Settings\\Section' => __DIR__ . '/..' . '/../lib/Settings/Section.php', 'OCA\\User_LDAP\\SetupChecks\\LdapConnection' => __DIR__ . '/..' . '/../lib/SetupChecks/LdapConnection.php', 'OCA\\User_LDAP\\SetupChecks\\LdapInvalidUuids' => __DIR__ . '/..' . '/../lib/SetupChecks/LdapInvalidUuids.php', + 'OCA\\User_LDAP\\Support\\SystemReportSection' => __DIR__ . '/..' . '/../lib/Support/SystemReportSection.php', 'OCA\\User_LDAP\\UserPluginManager' => __DIR__ . '/..' . '/../lib/UserPluginManager.php', 'OCA\\User_LDAP\\User\\DeletedUsersIndex' => __DIR__ . '/..' . '/../lib/User/DeletedUsersIndex.php', 'OCA\\User_LDAP\\User\\Manager' => __DIR__ . '/..' . '/../lib/User/Manager.php', diff --git a/apps/user_ldap/lib/AppInfo/Application.php b/apps/user_ldap/lib/AppInfo/Application.php index 7101c6b1cfee7..6d7d7ea686547 100644 --- a/apps/user_ldap/lib/AppInfo/Application.php +++ b/apps/user_ldap/lib/AppInfo/Application.php @@ -23,6 +23,7 @@ use OCA\User_LDAP\Notification\Notifier; use OCA\User_LDAP\SetupChecks\LdapConnection; use OCA\User_LDAP\SetupChecks\LdapInvalidUuids; +use OCA\User_LDAP\Support\SystemReportSection; use OCA\User_LDAP\User\Manager; use OCA\User_LDAP\User_Proxy; use OCA\User_LDAP\UserPluginManager; @@ -79,6 +80,7 @@ function (ContainerInterface $c) { $context->registerEventListener(PostLoginEvent::class, LoginListener::class); $context->registerSetupCheck(LdapInvalidUuids::class); $context->registerSetupCheck(LdapConnection::class); + $context->registerSystemReportSection(SystemReportSection::class); } #[\Override] diff --git a/apps/user_ldap/lib/Support/SystemReportSection.php b/apps/user_ldap/lib/Support/SystemReportSection.php new file mode 100644 index 0000000000000..3aa74bf342fcd --- /dev/null +++ b/apps/user_ldap/lib/Support/SystemReportSection.php @@ -0,0 +1,86 @@ +l10n->t('LDAP'); + } + + #[\Override] + public function getDetails(): array { + $configIds = $this->helper->getServerConfigurationPrefixes(); + if ($configIds === []) { + return []; + } + + $output = new BufferedOutput(); + foreach ($configIds as $id) { + $configHolder = new Configuration($id); + $output->write($this->renderConfiguration($id, $configHolder->getConfiguration())); + } + + return [ + new SystemReportDetail( + $this->l10n->t('LDAP configuration'), + $output->fetch(), + SystemReportDetailFormat::Preformatted, + ), + ]; + } + + /** @param array $configuration */ + public function renderConfiguration(string $id, array $configuration): string { + ksort($configuration); + + $rows = []; + foreach ($configuration as $key => $value) { + if ($key === 'ldapAgentPassword') { + $value = '***'; + } elseif (is_array($value)) { + $value = implode(';', $value); + } + $rows[] = [$key, $value]; + } + + $output = new BufferedOutput(); + $table = new Table($output); + $table->setHeaders(['Configuration', $id]); + $table->setRows($rows); + $table->render(); + + return $output->fetch(); + } +} diff --git a/build/rector-strict.php b/build/rector-strict.php index 7566ca1956a45..3ba2f3f13fa8c 100644 --- a/build/rector-strict.php +++ b/build/rector-strict.php @@ -50,6 +50,9 @@ $nextcloudDir . '/lib/public/AppFramework/ORM', $nextcloudDir . '/lib/private/AppFramework/ORM', $nextcloudDir . '/apps/oauth2', + $nextcloudDir . '/lib/public/SystemReport', + $nextcloudDir . '/lib/private/SystemReport', + $nextcloudDir . '/tests/lib/SystemReport', ]) ->withAutoloadPaths([ // ensure rector properly autoload the public interfaces diff --git a/lib/private/SystemReport/SystemReportManager.php b/lib/private/SystemReport/SystemReportManager.php index f87f35d0c75d1..13f82ac235037 100644 --- a/lib/private/SystemReport/SystemReportManager.php +++ b/lib/private/SystemReport/SystemReportManager.php @@ -10,27 +10,31 @@ namespace OC\SystemReport; use OC\AppFramework\Bootstrap\Coordinator; -use OCP\Server; use OCP\SystemReport\ISystemReportManager; use OCP\SystemReport\ISystemReportSection; +use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; -class SystemReportManager implements ISystemReportManager { +final readonly class SystemReportManager implements ISystemReportManager { public function __construct( - private readonly Coordinator $coordinator, - private readonly LoggerInterface $logger, + private Coordinator $coordinator, + private ContainerInterface $container, + private LoggerInterface $logger, ) { } + /** + * @return ISystemReportSection[] + */ #[\Override] public function getSections(): array { $sections = []; - $registrations = $this->coordinator->getRegistrationContext()->getSystemReportSections(); + $registrations = $this->coordinator->getRegistrationContext()?->getSystemReportSections() ?? []; foreach ($registrations as $registration) { $class = $registration->getService(); try { /** @var ISystemReportSection $section */ - $section = Server::get($class); + $section = $this->container->get($class); // Trigger detail collection here so a failing section is skipped // instead of surfacing later when the report is rendered. $section->getDetails(); @@ -38,8 +42,10 @@ public function getSections(): array { $this->logger->error('Exception while collecting system report section ' . $class . ': ' . $t->getMessage(), ['exception' => $t]); continue; } + $sections[] = $section; } + return $sections; } } diff --git a/lib/public/SystemReport/SystemReportDetail.php b/lib/public/SystemReport/SystemReportDetail.php index 0462706eb1aa0..c25b968cde0f0 100644 --- a/lib/public/SystemReport/SystemReportDetail.php +++ b/lib/public/SystemReport/SystemReportDetail.php @@ -14,7 +14,7 @@ * * @since 36.0.0 */ -final class SystemReportDetail { +final readonly class SystemReportDetail { /** * @param string $title Translated label of this detail * @param string $content Value of this detail. Must not contain secrets such as @@ -24,9 +24,9 @@ final class SystemReportDetail { * @since 36.0.0 */ public function __construct( - private readonly string $title, - private readonly string $content, - private readonly SystemReportDetailFormat $format = SystemReportDetailFormat::MultiLine, + private string $title, + private string $content, + private SystemReportDetailFormat $format = SystemReportDetailFormat::MultiLine, ) { } diff --git a/psalm-strict.xml b/psalm-strict.xml index 47b4de939a2b9..f467a4db66016 100644 --- a/psalm-strict.xml +++ b/psalm-strict.xml @@ -56,6 +56,9 @@ + + + diff --git a/tests/lib/SystemReport/SystemReportManagerTest.php b/tests/lib/SystemReport/SystemReportManagerTest.php index c45632b4d35e0..ffae227b5cc07 100644 --- a/tests/lib/SystemReport/SystemReportManagerTest.php +++ b/tests/lib/SystemReport/SystemReportManagerTest.php @@ -15,12 +15,18 @@ use OC\SystemReport\SystemReportManager; use OCP\SystemReport\ISystemReportSection; use PHPUnit\Framework\MockObject\MockObject; +use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; use Psr\Log\LoggerInterface; use Test\TestCase; -class SystemReportManagerTest extends TestCase { +final class SystemReportManagerTest extends TestCase { private Coordinator&MockObject $coordinator; + + private ContainerInterface&MockObject $container; + private LoggerInterface&MockObject $logger; + private SystemReportManager $manager; #[\Override] @@ -28,13 +34,18 @@ protected function setUp(): void { parent::setUp(); $this->coordinator = $this->createMock(Coordinator::class); + $this->container = $this->createMock(ContainerInterface::class); $this->logger = $this->createMock(LoggerInterface::class); $this->manager = new SystemReportManager( $this->coordinator, + $this->container, $this->logger, ); } + /** + * @param \OC\AppFramework\Bootstrap\ServiceRegistration[] $registrations + */ private function withRegisteredSections(array $registrations): void { $context = $this->createMock(RegistrationContext::class); $context->expects(self::atLeastOnce()) @@ -58,10 +69,13 @@ public function testGetSectionsResolvesAndReturnsRegisteredSections(): void { ->method('getDetails') ->willReturn([]); - \OC::$server->registerService('OCA\\Testing\\SystemReport\\FakeSection', fn () => $section, false); + $this->container->expects(self::once()) + ->method('get') + ->with($section::class) + ->willReturn($section); $this->withRegisteredSections([ - new ServiceRegistration('testing', 'OCA\\Testing\\SystemReport\\FakeSection'), + new ServiceRegistration('testing', $section::class), ]); $this->assertSame([$section], $this->manager->getSections()); @@ -72,10 +86,12 @@ public function testGetSectionsSkipsSectionThrowingDuringCollection(): void { $section->method('getDetails') ->willThrowException(new \RuntimeException('boom')); - \OC::$server->registerService('OCA\\Testing\\SystemReport\\ThrowingSection', fn () => $section, false); + $this->container->method('get') + ->with($section::class) + ->willReturn($section); $this->withRegisteredSections([ - new ServiceRegistration('testing', 'OCA\\Testing\\SystemReport\\ThrowingSection'), + new ServiceRegistration('testing', $section::class), ]); $this->logger->expects(self::once()) @@ -85,8 +101,12 @@ public function testGetSectionsSkipsSectionThrowingDuringCollection(): void { } public function testGetSectionsSkipsUnresolvableClass(): void { + $this->container->method('get') + ->with(\stdClass::class) + ->willThrowException($this->createStub(NotFoundExceptionInterface::class)); + $this->withRegisteredSections([ - new ServiceRegistration('testing', 'OCA\\Testing\\SystemReport\\DoesNotExist'), + new ServiceRegistration('testing', \stdClass::class), ]); $this->logger->expects(self::once())