mirror of
https://github.com/nextcloud/server.git
synced 2026-04-27 09:08:22 -04:00
fix(preview): Fix some tests
Signed-off-by: Carl Schwan <carl.schwan@nextcloud.com>
This commit is contained in:
parent
b0357663b9
commit
6f56dcf73e
14 changed files with 162 additions and 206 deletions
|
|
@ -52,7 +52,7 @@ class MovePreviewJob extends TimedJob {
|
|||
|
||||
private function doRun($argument): void {
|
||||
if ($this->appConfig->getValueBool('core', 'previewMovedDone')) {
|
||||
//return;
|
||||
return;
|
||||
}
|
||||
|
||||
$emptyHierarchicalPreviewFolders = false;
|
||||
|
|
@ -88,7 +88,7 @@ class MovePreviewJob extends TimedJob {
|
|||
$qb = $this->connection->getQueryBuilder();
|
||||
$qb->select('*')
|
||||
->from('filecache')
|
||||
->where($qb->expr()->like('path', $qb->createNamedParameter('appdata_%/preview/%/%.jpg')))
|
||||
->where($qb->expr()->like('path', $qb->createNamedParameter('appdata_%/preview/%/%.%')))
|
||||
->setMaxResults(100);
|
||||
|
||||
$result = $qb->executeQuery();
|
||||
|
|
@ -118,13 +118,13 @@ class MovePreviewJob extends TimedJob {
|
|||
}
|
||||
}
|
||||
|
||||
// Delete any left over preview directory
|
||||
// Delete any leftover preview directory
|
||||
$this->appData->getFolder('.')->delete();
|
||||
$this->appConfig->setValueBool('core', 'previewMovedDone', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string[]> $previewFolders
|
||||
* @param array<string|int, string[]> $previewFolders
|
||||
*/
|
||||
private function processPreviews(array $previewFolders, bool $simplePaths): void {
|
||||
foreach ($previewFolders as $fileId => $previewFolder) {
|
||||
|
|
|
|||
|
|
@ -35,23 +35,18 @@ class BackgroundCleanupJob extends TimedJob {
|
|||
}
|
||||
|
||||
public function run($argument): void {
|
||||
foreach ($this->getDeletedFiles() as $chunk) {
|
||||
foreach ($chunk as $storage => $fileIds) {
|
||||
foreach ($this->previewMapper->getByFileIds($storage, $fileIds) as $previews) {
|
||||
$previewIds = [];
|
||||
foreach ($previews as $preview) {
|
||||
$previewIds[] = $preview->getId();
|
||||
$this->storageFactory->deletePreview($preview);
|
||||
}
|
||||
|
||||
$this->previewMapper->deleteByIds($storage, $previewIds);
|
||||
};
|
||||
foreach ($this->getDeletedFiles() as $fileId) {
|
||||
$previewIds = [];
|
||||
foreach ($this->previewMapper->getByFileId($fileId) as $preview) {
|
||||
$previewIds[] = $preview->getId();
|
||||
$this->storageFactory->deletePreview($preview);
|
||||
}
|
||||
$this->previewMapper->deleteByIds($previewIds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Iterator<array<StorageId, FileId[]>>
|
||||
* @return \Iterator<FileId>
|
||||
*/
|
||||
private function getDeletedFiles(): \Iterator {
|
||||
if ($this->connection->getShardDefinition('filecache')) {
|
||||
|
|
@ -81,7 +76,7 @@ class BackgroundCleanupJob extends TimedJob {
|
|||
* If the related file is deleted, b.fileid will be null and the preview folder can be deleted.
|
||||
*/
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
$qb->select('p.storage_id', 'p.file_id')
|
||||
$qb->select('p.file_id')
|
||||
->from('previews', 'p')
|
||||
->leftJoin('p', 'filecache', 'f', $qb->expr()->eq(
|
||||
'p.file_id', 'f.fileid'
|
||||
|
|
@ -93,30 +88,14 @@ class BackgroundCleanupJob extends TimedJob {
|
|||
}
|
||||
|
||||
$cursor = $qb->executeQuery();
|
||||
|
||||
$lastStorageId = null;
|
||||
/** @var FileId[] $tmpResult */
|
||||
$tmpResult = [];
|
||||
while ($row = $cursor->fetch()) {
|
||||
if ($lastStorageId === null) {
|
||||
$lastStorageId = $row['storage_id'];
|
||||
} else if ($lastStorageId !== $row['storage_id']) {
|
||||
yield [$lastStorageId => $tmpResult];
|
||||
$tmpResult = [];
|
||||
$lastStorageId = $row['storage_id'];
|
||||
}
|
||||
$tmpResult[] = $row['file_id'];
|
||||
yield $row['file_id'];
|
||||
}
|
||||
|
||||
if (!empty($tmpResult)) {
|
||||
yield [$lastStorageId => $tmpResult];
|
||||
}
|
||||
|
||||
$cursor->closeCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Iterator<array<StorageId, FileId[]>>
|
||||
* @return \Iterator<FileId>
|
||||
*/
|
||||
private function getAllPreviewIds(int $chunkSize): \Iterator {
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
|
|
@ -131,20 +110,11 @@ class BackgroundCleanupJob extends TimedJob {
|
|||
$minId = 0;
|
||||
while (true) {
|
||||
$qb->setParameter('min_id', $minId);
|
||||
$rows = $qb->executeQuery()->fetchAll();
|
||||
if (count($rows) > 0) {
|
||||
$minId = $rows[count($rows) - 1]['id'];
|
||||
$result = [];
|
||||
foreach ($rows as $row) {
|
||||
if (!isset($result[$row['storage_id']])) {
|
||||
$result[$row['storage_id']] = [];
|
||||
}
|
||||
$result[$row['storage_id']][] = $row['file_id'];
|
||||
}
|
||||
yield $result;
|
||||
} else {
|
||||
break;
|
||||
$cursor = $qb->executeQuery();
|
||||
while ($row = $cursor->fetch()) {
|
||||
yield $row['file_id'];
|
||||
}
|
||||
$cursor->closeCursor();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace OC\Preview\Db;
|
||||
|
||||
use OC\Preview\Generator;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use OCP\AppFramework\Db\QBMapper;
|
||||
use OCP\DB\Exception;
|
||||
|
|
@ -28,6 +29,17 @@ class PreviewMapper extends QBMapper {
|
|||
parent::__construct($db, self::TABLE_NAME, Preview::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Generator<Preview>
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getAvailablePreviewForFile(int $fileId): \Generator {
|
||||
$selectQb = $this->db->getQueryBuilder();
|
||||
$this->joinLocation($selectQb)
|
||||
->where($selectQb->expr()->eq('p.file_id', $selectQb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
|
||||
yield from $this->yieldEntities($selectQb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int[] $fileIds
|
||||
* @return array<int, Preview[]>
|
||||
|
|
@ -37,7 +49,7 @@ class PreviewMapper extends QBMapper {
|
|||
$selectQb = $this->db->getQueryBuilder();
|
||||
$this->joinLocation($selectQb)
|
||||
->where(
|
||||
$selectQb->expr()->in('file_id', $selectQb->createNamedParameter($fileIds, IQueryBuilder::PARAM_INT_ARRAY)),
|
||||
$selectQb->expr()->in('p.file_id', $selectQb->createNamedParameter($fileIds, IQueryBuilder::PARAM_INT_ARRAY)),
|
||||
);
|
||||
$previews = array_fill_keys($fileIds, []);
|
||||
foreach ($this->yieldEntities($selectQb) as $preview) {
|
||||
|
|
@ -64,20 +76,13 @@ class PreviewMapper extends QBMapper {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param int[] $fileIds
|
||||
* @return array<int, Preview[]>
|
||||
* @return \Generator<Preview>
|
||||
*/
|
||||
public function getByFileIds(array $fileIds): array {
|
||||
public function getByFileId(int $fileId): \Generator {
|
||||
$selectQb = $this->db->getQueryBuilder();
|
||||
$this->joinLocation($selectQb)
|
||||
->where($selectQb->expr()->andX(
|
||||
$selectQb->expr()->in('file_id', $selectQb->createNamedParameter($fileIds, IQueryBuilder::PARAM_INT_ARRAY)),
|
||||
));
|
||||
$previews = array_fill_keys($fileIds, []);
|
||||
foreach ($this->yieldEntities($selectQb) as $preview) {
|
||||
$previews[$preview->getFileId()][] = $preview;
|
||||
}
|
||||
return $previews;
|
||||
->where($selectQb->expr()->eq('file_id', $selectQb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
|
||||
yield from $this->yieldEntities($selectQb);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -94,9 +99,9 @@ class PreviewMapper extends QBMapper {
|
|||
protected function joinLocation(IQueryBuilder $qb): IQueryBuilder {
|
||||
return $qb->select('p.*', 'l.bucket_name', 'l.object_store_name')
|
||||
->from(self::TABLE_NAME, 'p')
|
||||
->join('p', 'preview_locations', 'l', $qb->expr()->eq(
|
||||
'p.location_id', 'l.id'
|
||||
));
|
||||
->leftJoin('p', 'preview_locations', 'l', $qb->expr()->eq(
|
||||
'p.location_id', 'l.id'
|
||||
));
|
||||
}
|
||||
|
||||
public function getLocationId(string $bucket, string $objectStore): int {
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ class Generator {
|
|||
|
||||
try {
|
||||
return $this->savePreview($file, $preview->width(), $preview->height(), $crop, $max, $preview, $version);
|
||||
} catch (NotPermittedException $e) {
|
||||
} catch (NotPermittedException) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
}
|
||||
|
|
@ -571,6 +571,9 @@ class Generator {
|
|||
} else {
|
||||
$size = $this->storageFactory->writePreview($previewEntry, $preview->data());
|
||||
}
|
||||
if (!$size) {
|
||||
throw new \RuntimeException('Unable to write preview file');
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->previewMapper->delete($previewEntry);
|
||||
throw $e;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ use OC\Preview\Db\Preview;
|
|||
use OCP\IConfig;
|
||||
|
||||
class LocalPreviewStorage implements IPreviewStorage {
|
||||
private const PREVIEW_DIRECTORY = '__preview';
|
||||
private readonly string $rootFolder;
|
||||
private readonly string $instanceId;
|
||||
|
||||
|
|
@ -30,19 +29,18 @@ class LocalPreviewStorage implements IPreviewStorage {
|
|||
|
||||
public function writePreview(Preview $preview, $stream): false|int {
|
||||
$previewPath = $this->constructPath($preview);
|
||||
$this->createParentFiles($previewPath);
|
||||
$file = @fopen($this->getPreviewRootFolder() . $previewPath, 'w');
|
||||
return fwrite($file, $stream);
|
||||
if (!$this->createParentFiles($previewPath)) {
|
||||
return false;
|
||||
}
|
||||
return file_put_contents($previewPath, $stream);
|
||||
}
|
||||
|
||||
public function readPreview(Preview $preview) {
|
||||
$previewPath = $this->constructPath($preview);
|
||||
return @fopen($this->getPreviewRootFolder() . $previewPath, 'r');
|
||||
return @fopen($this->constructPath($preview), 'r');
|
||||
}
|
||||
|
||||
public function deletePreview(Preview $preview) {
|
||||
$previewPath = $this->constructPath($preview);
|
||||
@unlink($this->getPreviewRootFolder() . $previewPath);
|
||||
@unlink($this->constructPath($preview));
|
||||
}
|
||||
|
||||
public function getPreviewRootFolder(): string {
|
||||
|
|
@ -50,36 +48,28 @@ class LocalPreviewStorage implements IPreviewStorage {
|
|||
}
|
||||
|
||||
private function constructPath(Preview $preview): string {
|
||||
return implode('/', str_split(substr(md5((string)$preview->getFileId()), 0, 7))) . '/' . $preview->getFileId() . '/' . $preview->getName();
|
||||
return $this->getPreviewRootFolder() . implode('/', str_split(substr(md5((string)$preview->getFileId()), 0, 7))) . '/' . $preview->getFileId() . '/' . $preview->getName();
|
||||
}
|
||||
|
||||
private function createParentFiles($path) {
|
||||
['basename' => $basename, 'dirname' => $dirname] = pathinfo($path);
|
||||
$currentDir = $this->rootFolder . '/' . self::PREVIEW_DIRECTORY;
|
||||
mkdir($currentDir);
|
||||
foreach (explode('/', $dirname) as $suffix) {
|
||||
$currentDir .= "/$suffix";
|
||||
mkdir($currentDir);
|
||||
}
|
||||
private function createParentFiles(string $path): bool {
|
||||
['dirname' => $dirname] = pathinfo($path);
|
||||
return mkdir($dirname, recursive: true);
|
||||
}
|
||||
|
||||
public function migratePreview(Preview $preview, SimpleFile $file): void {
|
||||
$instanceId = $this->config->getSystemValueString('instanceid');
|
||||
$previewPath = $this->constructPath($preview);
|
||||
$sourcePath = $this->rootFolder . '/appdata_' . $instanceId . '/preview/' . $previewPath;
|
||||
$destinationPath = $this->rootFolder . '/' . self::PREVIEW_DIRECTORY . '/' . $previewPath;
|
||||
if (file_exists($sourcePath)) {
|
||||
return; // No need to migrate
|
||||
// legacy flat directory
|
||||
$sourcePath = $this->getPreviewRootFolder() . $preview->getFileId() . '/' . $preview->getName();
|
||||
if (!file_exists($sourcePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// legacy flat directory
|
||||
$sourcePath = $this->rootFolder . '/appdata_' . $instanceId . '/preview/' . $preview->getFileId() . '/' . $preview->getName();
|
||||
$destinationPath = $this->constructPath($preview);
|
||||
if (file_exists($destinationPath)) {
|
||||
@unlink($sourcePath); // We already have a new preview, just delete the old one
|
||||
return;
|
||||
}
|
||||
$this->createParentFiles($previewPath);
|
||||
echo 'Copying ' . $sourcePath . ' to ' . $destinationPath . PHP_EOL;
|
||||
|
||||
$this->createParentFiles($destinationPath);
|
||||
$ok = rename($sourcePath, $destinationPath);
|
||||
if (!$ok) {
|
||||
throw new LogicException('Failed to copy ' . $sourcePath . ' to ' . $destinationPath);
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ class ObjectStorePreviewStorage implements IPreviewStorage {
|
|||
public function migratePreview(Preview $preview, SimpleFile $file): void {
|
||||
// Just set the Preview::bucket and Preview::objectStore
|
||||
$this->getObjectStoreForPreview($preview, true);
|
||||
$this->previewMapper->update($preview);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OC\Preview\Storage;
|
||||
|
||||
use OC\Files\AppData\AppData;
|
||||
use OC\SystemConfig;
|
||||
use OCP\Files\IRootFolder;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\SimpleFS\ISimpleFolder;
|
||||
|
||||
class Root extends AppData {
|
||||
private $isMultibucketPreviewDistributionEnabled = false;
|
||||
public function __construct(IRootFolder $rootFolder, SystemConfig $systemConfig) {
|
||||
parent::__construct($rootFolder, $systemConfig, 'preview');
|
||||
|
||||
$this->isMultibucketPreviewDistributionEnabled = $systemConfig->getValue('objectstore.multibucket.preview-distribution', false) === true;
|
||||
}
|
||||
|
||||
|
||||
public function getFolder(string $name): ISimpleFolder {
|
||||
$internalFolder = self::getInternalFolder($name);
|
||||
|
||||
try {
|
||||
return parent::getFolder($internalFolder);
|
||||
} catch (NotFoundException $e) {
|
||||
/*
|
||||
* The new folder structure is not found.
|
||||
* Lets try the old one
|
||||
*/
|
||||
}
|
||||
|
||||
try {
|
||||
return parent::getFolder($name);
|
||||
} catch (NotFoundException $e) {
|
||||
/*
|
||||
* The old folder structure is not found.
|
||||
* Lets try the multibucket fallback if available
|
||||
*/
|
||||
if ($this->isMultibucketPreviewDistributionEnabled) {
|
||||
return parent::getFolder('old-multibucket/' . $internalFolder);
|
||||
}
|
||||
|
||||
// when there is no further fallback just throw the exception
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function newFolder(string $name): ISimpleFolder {
|
||||
$internalFolder = self::getInternalFolder($name);
|
||||
return parent::newFolder($internalFolder);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not allow directory listing on this special root
|
||||
* since it gets to big and time consuming
|
||||
*/
|
||||
public function getDirectoryListing(): array {
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function getInternalFolder(string $name): string {
|
||||
return implode('/', str_split(substr(md5($name), 0, 7))) . '/' . $name;
|
||||
}
|
||||
|
||||
public function getStorageId(): int {
|
||||
return $this->getAppDataRootFolder()->getStorage()->getCache()->getNumericStorageId();
|
||||
}
|
||||
}
|
||||
|
|
@ -8,11 +8,11 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace OC\Preview;
|
||||
|
||||
use OC\Preview\Db\PreviewMapper;
|
||||
use OC\Preview\Storage\StorageFactory;
|
||||
use OCP\Files\FileInfo;
|
||||
use OCP\Files\Folder;
|
||||
use OCP\Files\IAppData;
|
||||
use OCP\Files\Node;
|
||||
use OCP\Files\NotFoundException;
|
||||
|
||||
/**
|
||||
* Class Watcher
|
||||
|
|
@ -22,40 +22,36 @@ use OCP\Files\NotFoundException;
|
|||
* Class that will watch filesystem activity and remove previews as needed.
|
||||
*/
|
||||
class Watcher {
|
||||
/** @var IAppData */
|
||||
private $appData;
|
||||
|
||||
/**
|
||||
* Watcher constructor.
|
||||
*
|
||||
* @param IAppData $appData
|
||||
*/
|
||||
public function __construct(IAppData $appData) {
|
||||
$this->appData = $appData;
|
||||
public function __construct(
|
||||
readonly private StorageFactory $storageFactory,
|
||||
readonly private PreviewMapper $previewMapper,
|
||||
) {
|
||||
}
|
||||
|
||||
public function postWrite(Node $node) {
|
||||
public function postWrite(Node $node): void {
|
||||
$this->deleteNode($node);
|
||||
}
|
||||
|
||||
protected function deleteNode(FileInfo $node) {
|
||||
protected function deleteNode(FileInfo $node): void {
|
||||
// We only handle files
|
||||
if ($node instanceof Folder) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (is_null($node->getId())) {
|
||||
return;
|
||||
}
|
||||
$folder = $this->appData->getFolder((string)$node->getId());
|
||||
$folder->delete();
|
||||
} catch (NotFoundException $e) {
|
||||
//Nothing to do
|
||||
if (is_null($node->getId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
[$node->getId() => $previews] = $this->previewMapper->getAvailablePreviews([$node->getId()]);
|
||||
foreach ($previews as $preview) {
|
||||
$this->storageFactory->deletePreview($preview);
|
||||
}
|
||||
}
|
||||
|
||||
public function versionRollback(array $data) {
|
||||
public function versionRollback(array $data): void {
|
||||
if (isset($data['node'])) {
|
||||
$this->deleteNode($data['node']);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ use function array_key_exists;
|
|||
class PreviewManager implements IPreview {
|
||||
protected IConfig $config;
|
||||
protected IRootFolder $rootFolder;
|
||||
protected IAppData $appData;
|
||||
protected IEventDispatcher $eventDispatcher;
|
||||
private ?Generator $generator = null;
|
||||
private GeneratorHelper $helper;
|
||||
|
|
@ -59,7 +58,6 @@ class PreviewManager implements IPreview {
|
|||
public function __construct(
|
||||
IConfig $config,
|
||||
IRootFolder $rootFolder,
|
||||
IAppData $appData,
|
||||
IEventDispatcher $eventDispatcher,
|
||||
GeneratorHelper $helper,
|
||||
?string $userId,
|
||||
|
|
@ -70,7 +68,6 @@ class PreviewManager implements IPreview {
|
|||
) {
|
||||
$this->config = $config;
|
||||
$this->rootFolder = $rootFolder;
|
||||
$this->appData = $appData;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->helper = $helper;
|
||||
$this->userId = $userId;
|
||||
|
|
|
|||
|
|
@ -82,9 +82,11 @@ use OC\Notification\Manager;
|
|||
use OC\OCM\Model\OCMProvider;
|
||||
use OC\OCM\OCMDiscoveryService;
|
||||
use OC\OCS\DiscoveryService;
|
||||
use OC\Preview\Db\PreviewMapper;
|
||||
use OC\Preview\GeneratorHelper;
|
||||
use OC\Preview\IMagickSupport;
|
||||
use OC\Preview\MimeIconProvider;
|
||||
use OC\Preview\Watcher;
|
||||
use OC\Profile\ProfileManager;
|
||||
use OC\Profiler\Profiler;
|
||||
use OC\Remote\Api\ApiFactory;
|
||||
|
|
@ -291,10 +293,6 @@ class Server extends ServerContainer implements IServerContainer {
|
|||
return new PreviewManager(
|
||||
$c->get(\OCP\IConfig::class),
|
||||
$c->get(IRootFolder::class),
|
||||
new \OC\Preview\Storage\Root(
|
||||
$c->get(IRootFolder::class),
|
||||
$c->get(SystemConfig::class)
|
||||
),
|
||||
$c->get(IEventDispatcher::class),
|
||||
$c->get(GeneratorHelper::class),
|
||||
$c->get(ISession::class)->get('user_id'),
|
||||
|
|
@ -306,12 +304,10 @@ class Server extends ServerContainer implements IServerContainer {
|
|||
});
|
||||
$this->registerAlias(IMimeIconProvider::class, MimeIconProvider::class);
|
||||
|
||||
$this->registerService(\OC\Preview\Watcher::class, function (ContainerInterface $c) {
|
||||
return new \OC\Preview\Watcher(
|
||||
new \OC\Preview\Storage\Root(
|
||||
$c->get(IRootFolder::class),
|
||||
$c->get(SystemConfig::class)
|
||||
)
|
||||
$this->registerService(Watcher::class, function (ContainerInterface $c): Watcher {
|
||||
return new Watcher(
|
||||
$c->get(\OC\Preview\Storage\StorageFactory::class),
|
||||
$c->get(PreviewMapper::class),
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,11 @@ class BackgroundCleanupJobTest extends \Test\TestCase {
|
|||
|
||||
$this->logout();
|
||||
|
||||
foreach ($this->previewMapper->getAvailablePreviews(5) as $preview) {
|
||||
$this->previewStorageFactory->deletePreview($preview);
|
||||
$this->previewMapper->delete($preview);
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +94,7 @@ class BackgroundCleanupJobTest extends \Test\TestCase {
|
|||
$userFolder = $this->rootFolder->getUserFolder($this->userId);
|
||||
|
||||
$files = [];
|
||||
for ($i = 0; $i < 11; $i++) {
|
||||
foreach (range(0, 10) as $i) {
|
||||
$file = $userFolder->newFile($i . '.txt');
|
||||
$file->putContent('hello world!');
|
||||
$this->previewManager->getPreview($file);
|
||||
|
|
|
|||
|
|
@ -3,11 +3,17 @@
|
|||
namespace lib\Preview;
|
||||
|
||||
use OC\Core\BackgroundJobs\MovePreviewJob;
|
||||
use OC\Preview\Db\PreviewMapper;
|
||||
use OC\Preview\Storage\StorageFactory;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\Files\AppData\IAppDataFactory;
|
||||
use OCP\Files\IAppData;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Server;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Test\TestCase;
|
||||
|
||||
/**
|
||||
|
|
@ -16,17 +22,78 @@ use Test\TestCase;
|
|||
#[CoversClass(MovePreviewJob::class)]
|
||||
class MovePreviewJobTest extends TestCase {
|
||||
private IAppData $previewAppData;
|
||||
private PreviewMapper $previewMapper;
|
||||
private IAppConfig&MockObject $appConfig;
|
||||
private StorageFactory $storageFactory;
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->previewAppData = Server::get(IAppDataFactory::class)->get('preview');
|
||||
$this->previewMapper = Server::get(PreviewMapper::class);
|
||||
$this->appConfig = $this->createMock(IAppConfig::class);
|
||||
$this->appConfig->expects($this->any())
|
||||
->method('getValueBool')
|
||||
->willReturn(false);
|
||||
$this->storageFactory = Server::get(StorageFactory::class);
|
||||
}
|
||||
|
||||
#[TestDox("Test the migration from the legacy flat hierarchy to the new one")]
|
||||
public function tearDown(): void {
|
||||
foreach ($this->previewMapper->getAvailablePreviewForFile(5) as $preview) {
|
||||
$this->storageFactory->deletePreview($preview);
|
||||
$this->previewMapper->delete($preview);
|
||||
}
|
||||
|
||||
foreach ($this->previewAppData->getDirectoryListing() as $folder) {
|
||||
$folder->delete();
|
||||
}
|
||||
}
|
||||
|
||||
#[TestDox("Test the migration from the legacy flat hierarchy to the new database format")]
|
||||
function testMigrationLegacyPath(): void {
|
||||
$folder = $this->previewAppData->newFolder(5);
|
||||
$file = $folder->newFile('64-64-crop.png', 'abcdefg');
|
||||
$job = Server::get(MovePreviewJob::class);
|
||||
$this->invokePrivate($job, 'run', []);
|
||||
$folder->newFile('64-64-crop.jpg', 'abcdefg');
|
||||
$folder->newFile('128-128-crop.png', 'abcdefg');
|
||||
$this->assertEquals(1, count($this->previewAppData->getDirectoryListing()));
|
||||
$this->assertEquals(2, count($folder->getDirectoryListing()));
|
||||
$this->assertEquals(0, count(iterator_to_array($this->previewMapper->getAvailablePreviewForFile(5))));
|
||||
|
||||
$job = new MovePreviewJob(
|
||||
Server::get(ITimeFactory::class),
|
||||
$this->appConfig,
|
||||
$this->previewMapper,
|
||||
$this->storageFactory,
|
||||
Server::get(IDBConnection::class),
|
||||
Server::get(IAppDataFactory::class)
|
||||
);
|
||||
$this->invokePrivate($job, 'run', [[]]);
|
||||
$this->assertEquals(0, count($this->previewAppData->getDirectoryListing()));
|
||||
$this->assertEquals(2, count(iterator_to_array($this->previewMapper->getAvailablePreviewForFile(5))));
|
||||
}
|
||||
|
||||
private static function getInternalFolder(string $name): string {
|
||||
return implode('/', str_split(substr(md5($name), 0, 7))) . '/' . $name;
|
||||
}
|
||||
|
||||
#[TestDox("Test the migration from the 'new' nested hierarchy to the database format")]
|
||||
function testMigrationPath(): void {
|
||||
$folder = $this->previewAppData->newFolder(self::getInternalFolder(5));
|
||||
$folder->newFile('64-64-crop.jpg', 'abcdefg');
|
||||
$folder->newFile('128-128-crop.png', 'abcdefg');
|
||||
|
||||
$folder = $this->previewAppData->getFolder(self::getInternalFolder(5));
|
||||
$this->assertEquals(2, count($folder->getDirectoryListing()));
|
||||
$this->assertEquals(0, count(iterator_to_array($this->previewMapper->getAvailablePreviewForFile(5))));
|
||||
|
||||
$job = new MovePreviewJob(
|
||||
Server::get(ITimeFactory::class),
|
||||
$this->appConfig,
|
||||
$this->previewMapper,
|
||||
$this->storageFactory,
|
||||
Server::get(IDBConnection::class),
|
||||
Server::get(IAppDataFactory::class)
|
||||
);
|
||||
$this->invokePrivate($job, 'run', [[]]);
|
||||
$this->assertEquals(0, count($this->previewAppData->getDirectoryListing()));
|
||||
$this->assertEquals(2, count(iterator_to_array($this->previewMapper->getAvailablePreviewForFile(5))));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ class PreviewMapperTest extends TestCase {
|
|||
$qb = $this->connection->getQueryBuilder();
|
||||
$qb->insert('preview_locations')
|
||||
->values([
|
||||
'bucket' => $qb->createNamedParameter('preview-' . $bucket),
|
||||
'object_store' => $qb->createNamedParameter('default'),
|
||||
'bucket_name' => $qb->createNamedParameter('preview-' . $bucket),
|
||||
'object_store_name' => $qb->createNamedParameter('default'),
|
||||
]);
|
||||
$locationId = $qb->executeStatement();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patch level
|
||||
// when updating major/minor version number.
|
||||
|
||||
$OC_Version = [33, 0, 0, 0];
|
||||
$OC_Version = [33, 0, 0, 1];
|
||||
|
||||
// The human-readable string
|
||||
$OC_VersionString = '33.0.0 dev';
|
||||
|
|
|
|||
Loading…
Reference in a new issue