diff --git a/apps/settings/tests/UserMigration/AccountMigratorTest.php b/apps/settings/tests/UserMigration/AccountMigratorTest.php index c668bb9e6af15..045a0cf3ded1a 100644 --- a/apps/settings/tests/UserMigration/AccountMigratorTest.php +++ b/apps/settings/tests/UserMigration/AccountMigratorTest.php @@ -30,6 +30,7 @@ use OCA\Settings\UserMigration\AccountMigrator; use OCP\Accounts\IAccountManager; use OCP\AppFramework\App; +use OCP\IAvatarManager; use OCP\IUserManager; use OCP\UserMigration\IExportDestination; use OCP\UserMigration\IImportSource; @@ -45,6 +46,8 @@ class AccountMigratorTest extends TestCase { private IUserManager $userManager; + private IAvatarManager $avatarManager; + private AccountMigrator $migrator; /** @var IImportSource|MockObject */ @@ -58,13 +61,16 @@ class AccountMigratorTest extends TestCase { private const ASSETS_DIR = __DIR__ . '/assets/'; - private const REGEX_ACCOUNT_FILE = '/' . Application::APP_ID . '\/' . '[a-z]+\.json' . '/'; + private const REGEX_ACCOUNT_FILE = '/^' . Application::APP_ID . '\/' . '[a-z]+\.json' . '$/'; + + private const REGEX_AVATAR_FILE = '/^' . Application::APP_ID . '\/' . 'avatar\.(jpg|png)' . '$/'; protected function setUp(): void { $app = new App(Application::APP_ID); $container = $app->getContainer(); $this->userManager = $container->get(IUserManager::class); + $this->avatarManager = $container->get(IAvatarManager::class); $this->migrator = $container->get(AccountMigrator::class); $this->importSource = $this->createMock(IImportSource::class); @@ -74,14 +80,20 @@ protected function setUp(): void { public function dataImportExportAccount(): array { return array_map( - fn (string $filename) => [ - UUIDUtil::getUUID(), - json_decode(file_get_contents(self::ASSETS_DIR . $filename), true, 512, JSON_THROW_ON_ERROR), - ], - array_diff( + function (string $filename) { + $dataPath = self::ASSETS_DIR . $filename; + // For each json file there is an avatar image with the same basename + $avatarBasename = pathinfo($filename, PATHINFO_FILENAME); + $avatarPath = self::ASSETS_DIR . (file_exists(self::ASSETS_DIR . "$avatarBasename.jpg") ? "$avatarBasename.jpg" : "$avatarBasename.png"); + return [ + UUIDUtil::getUUID(), + json_decode(file_get_contents($dataPath), true, 512, JSON_THROW_ON_ERROR), + $avatarPath, + ]; + }, + array_filter( scandir(self::ASSETS_DIR), - // Exclude current and parent directories - ['.', '..'], + fn (string $filename) => pathinfo($filename, PATHINFO_EXTENSION) === 'json', ), ); } @@ -89,8 +101,9 @@ public function dataImportExportAccount(): array { /** * @dataProvider dataImportExportAccount */ - public function testImportExportAccount(string $userId, array $importData): void { + public function testImportExportAccount(string $userId, array $importData, string $avatarPath): void { $user = $this->userManager->createUser($userId, 'topsecretpassword'); + $avatarExt = pathinfo($avatarPath, PATHINFO_EXTENSION); $exportData = $importData; // Verification status of email will be set to in progress on import so we set the export data to reflect that $exportData[IAccountManager::PROPERTY_EMAIL]['verified'] = IAccountManager::VERIFICATION_IN_PROGRESS; @@ -107,14 +120,47 @@ public function testImportExportAccount(string $userId, array $importData): void ->with($this->matchesRegularExpression(self::REGEX_ACCOUNT_FILE)) ->willReturn(json_encode($importData)); + $this->importSource + ->expects($this->once()) + ->method('getFolderListing') + ->with(Application::APP_ID . '/') + ->willReturn(["avatar.$avatarExt"]); + + $this->importSource + ->expects($this->once()) + ->method('getFileAsStream') + ->with($this->matchesRegularExpression(self::REGEX_AVATAR_FILE)) + ->willReturn(fopen($avatarPath, 'r')); + $this->migrator->import($user, $this->importSource, $this->output); + $importedAvatar = $this->avatarManager->getAvatar($user->getUID()); + $this->assertTrue($importedAvatar->isCustomAvatar()); + + /** + * Avatar images are re-encoded on import therefore JPEG images which use lossy compression cannot be checked for equality + * @see https://github.com/nextcloud/server/blob/9644b7e505dc90a1e683f77ad38dc6dc4e90fa2f/lib/private/legacy/OC_Image.php#L383-L390 + */ + + if ($avatarExt !== 'jpg') { + $this->assertStringEqualsFile( + $avatarPath, + $importedAvatar->getFile(-1)->getContent(), + ); + } + $this->exportDestination ->expects($this->once()) ->method('addFileContents') ->with($this->matchesRegularExpression(self::REGEX_ACCOUNT_FILE), json_encode($exportData)) ->willReturn(true); + $this->exportDestination + ->expects($this->once()) + ->method('addFileAsStream') + ->with($this->matchesRegularExpression(self::REGEX_AVATAR_FILE), $this->isType('resource')) + ->willReturn(true); + $this->migrator->export($user, $this->exportDestination, $this->output); } } diff --git a/apps/settings/tests/UserMigration/assets/account-complex.jpg b/apps/settings/tests/UserMigration/assets/account-complex.jpg new file mode 100644 index 0000000000000..bece3675c11d2 Binary files /dev/null and b/apps/settings/tests/UserMigration/assets/account-complex.jpg differ diff --git a/apps/settings/tests/UserMigration/assets/account.png b/apps/settings/tests/UserMigration/assets/account.png new file mode 100644 index 0000000000000..12226f1433476 Binary files /dev/null and b/apps/settings/tests/UserMigration/assets/account.png differ