From 6388179d2e2531fc884c1db1e2744f4b40c678be Mon Sep 17 00:00:00 2001 From: Daniel Kesselberg Date: Sun, 21 Jun 2026 21:30:48 +0200 Subject: [PATCH] fix(dav): Handle GenericFileException when reading default contact file Assisted-by: ClaudeCode:claude-sonnet-4-6 Signed-off-by: Daniel Kesselberg --- .../dav/lib/Service/ExampleContactService.php | 12 ++++-- apps/dav/lib/Service/ExampleEventService.php | 3 +- .../Service/ExampleContactServiceTest.php | 39 ++++++++++++++++++- .../unit/Service/ExampleEventServiceTest.php | 25 ++++++++++++ 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/apps/dav/lib/Service/ExampleContactService.php b/apps/dav/lib/Service/ExampleContactService.php index 2ae003b9deddf..d86ed5ac7d7e8 100644 --- a/apps/dav/lib/Service/ExampleContactService.php +++ b/apps/dav/lib/Service/ExampleContactService.php @@ -13,9 +13,12 @@ use OCA\DAV\CardDAV\CardDavBackend; use OCP\AppFramework\Services\IAppConfig; use OCP\Files\AppData\IAppDataFactory; +use OCP\Files\GenericFileException; use OCP\Files\IAppData; use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; use OCP\IL10N; +use OCP\Lock\LockedException; use Psr\Log\LoggerInterface; use Symfony\Component\Uid\Uuid; @@ -47,11 +50,14 @@ public function getCard(): ?string { return null; } - if (!$folder->fileExists('defaultContact.vcf')) { + try { + return $folder->getFile('defaultContact.vcf')->getContent(); + } catch (NotFoundException $e) { + return null; + } catch (GenericFileException|NotPermittedException|LockedException $e) { + $this->logger->error('Could not read default contact file', ['exception' => $e]); return null; } - - return $folder->getFile('defaultContact.vcf')->getContent(); } private function createInitialDefaultContact(): void { diff --git a/apps/dav/lib/Service/ExampleEventService.php b/apps/dav/lib/Service/ExampleEventService.php index 3b2b07fe416c2..12765d202684f 100644 --- a/apps/dav/lib/Service/ExampleEventService.php +++ b/apps/dav/lib/Service/ExampleEventService.php @@ -14,6 +14,7 @@ use OCA\DAV\Exception\ExampleEventException; use OCA\DAV\Model\ExampleEvent; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Files\GenericFileException; use OCP\Files\IAppData; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; @@ -105,7 +106,7 @@ private function getCustomExampleEvent(): ?string { try { return $icsFile->getContent(); - } catch (NotFoundException|NotPermittedException $e) { + } catch (NotFoundException|NotPermittedException|GenericFileException $e) { throw new ExampleEventException( 'Failed to read custom example event', 0, diff --git a/apps/dav/tests/unit/Service/ExampleContactServiceTest.php b/apps/dav/tests/unit/Service/ExampleContactServiceTest.php index 757f55f8b5118..6dc747c3744ba 100644 --- a/apps/dav/tests/unit/Service/ExampleContactServiceTest.php +++ b/apps/dav/tests/unit/Service/ExampleContactServiceTest.php @@ -11,9 +11,9 @@ use OCA\DAV\CardDAV\CardDavBackend; use OCA\DAV\Service\ExampleContactService; -use OCP\App\IAppManager; use OCP\AppFramework\Services\IAppConfig; use OCP\Files\AppData\IAppDataFactory; +use OCP\Files\GenericFileException; use OCP\Files\IAppData; use OCP\Files\NotFoundException; use OCP\Files\SimpleFS\ISimpleFile; @@ -27,7 +27,6 @@ class ExampleContactServiceTest extends TestCase { protected ExampleContactService $service; protected CardDavBackend&MockObject $cardDav; - protected IAppManager&MockObject $appManager; protected IAppDataFactory&MockObject $appDataFactory; protected LoggerInterface&MockObject $logger; protected IAppConfig&MockObject $appConfig; @@ -161,6 +160,42 @@ public function testUidAndRevAreAddedIfMissing(): void { $this->assertTrue(Uuid::isValid($vcard->UID->getValue())); } + public function testGetCardReturnsNullWhenFolderNotFound(): void { + $this->appData->method('getFolder')->willThrowException(new NotFoundException()); + $this->assertNull($this->service->getCard()); + } + + public function testGetCardReturnsNullWhenFileNotFound(): void { + $folder = $this->createMock(ISimpleFolder::class); + $this->appData->method('getFolder')->willReturn($folder); + $folder->method('getFile')->willThrowException(new NotFoundException()); + $this->assertNull($this->service->getCard()); + } + + public function testGetCardReturnsNullOnReadError(): void { + $folder = $this->createMock(ISimpleFolder::class); + $file = $this->createMock(ISimpleFile::class); + $this->appData->method('getFolder')->willReturn($folder); + $folder->method('getFile')->willReturn($file); + $file->method('getContent')->willThrowException(new GenericFileException()); + + $this->logger->expects($this->once()) + ->method('error') + ->with('Could not read default contact file', $this->anything()); + + $this->assertNull($this->service->getCard()); + } + + public function testGetCardReturnsContent(): void { + $folder = $this->createMock(ISimpleFolder::class); + $file = $this->createMock(ISimpleFile::class); + $this->appData->method('getFolder')->willReturn($folder); + $folder->method('getFile')->willReturn($file); + $file->method('getContent')->willReturn('vcarddata'); + + $this->assertEquals('vcarddata', $this->service->getCard()); + } + public function testDefaultContactIsNotCreatedIfEnabled(): void { $this->appConfig->method('getAppValueBool') ->with('enableDefaultContact', true) diff --git a/apps/dav/tests/unit/Service/ExampleEventServiceTest.php b/apps/dav/tests/unit/Service/ExampleEventServiceTest.php index a6e080217eb7e..8034756e5f866 100644 --- a/apps/dav/tests/unit/Service/ExampleEventServiceTest.php +++ b/apps/dav/tests/unit/Service/ExampleEventServiceTest.php @@ -10,8 +10,10 @@ namespace OCA\DAV\Tests\unit\Service; use OCA\DAV\CalDAV\CalDavBackend; +use OCA\DAV\Exception\ExampleEventException; use OCA\DAV\Service\ExampleEventService; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Files\GenericFileException; use OCP\Files\IAppData; use OCP\Files\NotFoundException; use OCP\Files\SimpleFS\ISimpleFile; @@ -173,6 +175,29 @@ public function testGetExampleEventWithCustomEvent($customEventIcs): void { $this->assertEquals($expectedIcs, $actualIcs); } + public function testGetExampleEventThrowsOnReadError(): void { + $exampleEventFolder = $this->createMock(ISimpleFolder::class); + $this->appData->expects(self::once()) + ->method('getFolder') + ->with('example_event') + ->willReturn($exampleEventFolder); + $exampleEventFile = $this->createMock(ISimpleFile::class); + $exampleEventFolder->expects(self::once()) + ->method('getFile') + ->with('example_event.ics') + ->willReturn($exampleEventFile); + $exampleEventFile->expects(self::once()) + ->method('getContent') + ->willThrowException(new GenericFileException()); + + $this->random->expects(self::once()) + ->method('generate') + ->willReturn('RANDOM-UID'); + + $this->expectException(ExampleEventException::class); + $this->service->getExampleEvent(); + } + public function testGetExampleEventWithDefault(): void { $this->appData->expects(self::once()) ->method('getFolder')