nextcloud-custom-apps-face-.../git_facerecognition/tests/Integration/ImageProcessingTaskTest.php
2024-09-03 09:12:12 +05:00

206 lines
8.5 KiB
PHP

<?php
/**
* @copyright Copyright (c) 2017, Matias De lellis <mati86dl@gmail.com>
* @copyright Copyright (c) 2018, Branko Kokanovic <branko@kokanovic.org>
*
* @author Branko Kokanovic <branko@kokanovic.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\FaceRecognition\Tests\Integration;
use OC;
use OC\Files\View;
use OCP\IConfig;
use OCP\IUser;
use OCP\AppFramework\App;
use OCP\AppFramework\IAppContainer;
use OCA\FaceRecognition\BackgroundJob\FaceRecognitionContext;
use OCA\FaceRecognition\BackgroundJob\FaceRecognitionLogger;
use OCA\FaceRecognition\BackgroundJob\Tasks\AddMissingImagesTask;
use OCA\FaceRecognition\BackgroundJob\Tasks\ImageProcessingTask;
use OCA\FaceRecognition\Db\Image;
use OCA\FaceRecognition\Model\ModelManager;
use Test\TestCase;
class ImageProcessingTaskTest extends IntegrationTestCase {
public function setUp(): void {
parent::setUp();
// Since test is changing this values, try to preserve old values (this is best effort)
$this->originalMinImageSize = intval($this->config->getAppValue('facerecognition', 'min_image_size', '512'));
$this->originalMaxImageArea = intval($this->config->getAppValue('facerecognition', 'max_image_area', 0));
$this->config->setAppValue('facerecognition', 'min_image_size', 1);
$this->config->setAppValue('facerecognition', 'max_image_area', 200 * 200);
// Install models needed to test
$model = $this->container->query('OCA\FaceRecognition\Model\DlibCnnModel\DlibCnn5Model');
$model->install();
}
public function tearDown(): void {
$this->config->setAppValue('facerecognition', 'min_image_size', $this->originalMinImageSize);
$this->config->setAppValue('facerecognition', 'max_image_area', $this->originalMaxImageArea);
parent::tearDown();
}
/**
* Tests when image cannot be loaded at all
* (tests whether image is declared as processed and error is added to it)
*/
public function testInvalidImage() {
$image = $this->genericTestImageProcessing('bogus image data', true, 0);
// Invalid image should have 0 as processing duration
$this->assertEquals(0, $image->getProcessingDuration());
}
/**
* Tests that small images are skipped during processing
*/
public function testImageTooSmallToProcess() {
$this->config->setAppValue('facerecognition', 'min_image_size', 10000);
$imgData = file_get_contents(\OC::$SERVERROOT . '/apps/facerecognition/tests/assets/lenna.jpg');
$image = $this->genericTestImageProcessing($imgData, false, 0);
}
/**
* Test when there is no faces on image
* (image should be declared as processed, but 0 faces should be associated with it)
*/
public function testNoFacesFound() {
$imgData = file_get_contents(\OC::$SERVERROOT . '/apps/facerecognition/tests/assets/black.jpg');
$image = $this->genericTestImageProcessing($imgData, false, 0);
}
/**
* Regular positive test that find one face in image
*/
public function testFindFace() {
$imgData = file_get_contents(\OC::$SERVERROOT . '/apps/facerecognition/tests/assets/lenna.jpg');
$image = $this->genericTestImageProcessing($imgData, false, 1);
// Check exact values for face boundaries (might need to update when we bump dlib/pdlib versions)
$faceMapper = $this->container->query('OCA\FaceRecognition\Db\FaceMapper');
$face = $faceMapper->getFaces($this->user->getUID(), ModelManager::DEFAULT_FACE_MODEL_ID)[0];
$face = $faceMapper->find($face->getId());
$this->assertEquals(49, $face->getX());
$this->assertEquals(62, $face->getY());
$this->assertEquals(75, $face->getWidth());
$this->assertEquals(75, $face->getHeight());
}
/**
* Helper function that asserts in generic fashion whatever necessary.
*
* @param string|resource $imgData Image data that will be analyzed
* @param bool $expectingError True if we should assert that error is found, false if we should assert there is no error
* @param int $expectedFacesCount Number of faces that we should assert that should be found in processed image
*
* @return Image One found image
*/
private function genericTestImageProcessing($imgData, $expectingError, $expectedFacesCount) {
$imageMapper = $this->container->query('OCA\FaceRecognition\Db\ImageMapper');
$faceMapper = $this->container->query('OCA\FaceRecognition\Db\FaceMapper');
$this->doImageProcessing($imgData);
// Check that there is no unprocessed images
$this->assertEquals(0, count($imageMapper->findImagesWithoutFaces($this->user, ModelManager::DEFAULT_FACE_MODEL_ID)));
// Check image fields after processing
$images = $imageMapper->findImages($this->user->getUID(), ModelManager::DEFAULT_FACE_MODEL_ID);
$this->assertEquals(1, count($images));
$image = $imageMapper->find($this->user->getUID(), $images[0]->getId());
$this->assertTrue(is_null($image->getError()) xor $expectingError);
$this->assertTrue($image->getIsProcessed());
$this->assertNotNull(0, $image->getProcessingDuration());
$this->assertNotNull($image->getLastProcessedTime());
// Check number of found faces
$this->assertEquals($expectedFacesCount, count($faceMapper->getFaces($this->user->getUID(), ModelManager::DEFAULT_FACE_MODEL_ID)));
return $image;
}
/**
* Helper method to set up and do image processing
*
* @param string|resource $imgData Image data that will be analyzed
* @param IUser|null $contextUser Optional user to process images for.
* If not given, images for all users will be processed.
*/
private function doImageProcessing($imgData, $contextUser = null) {
// Create ImageProcessingTask
$imageMapper = $this->container->query('OCA\FaceRecognition\Db\ImageMapper');
$fileService = $this->container->query('OCA\FaceRecognition\Service\FileService');
$settingsService = $this->container->query('OCA\FaceRecognition\Service\SettingsService');
$modelManager = $this->container->query('OCA\FaceRecognition\Model\ModelManager');
$lockingProvider = $this->container->query('OCP\Lock\ILockingProvider');
$imageProcessingTask = new ImageProcessingTask($imageMapper, $fileService, $settingsService, $modelManager, $lockingProvider);
$this->assertNotEquals("", $imageProcessingTask->description());
// Set user for which to do processing, if any
$this->context->user = $contextUser;
// Upload file
$this->loginAsUser($this->user->getUID());
$view = new View('/' . $this->user->getUID() . '/files');
$view->file_put_contents("foo1.jpg", $imgData);
// Scan it, so it is in database, ready to be processed
$this->doMissingImageScan($this->user);
$this->context->propertyBag['images'] = $imageMapper->findImagesWithoutFaces($this->user, ModelManager::DEFAULT_FACE_MODEL_ID);
$this->assertEquals(1, count($this->context->propertyBag['images']));
// Since this task returns generator, iterate until it is done
$generator = $imageProcessingTask->execute($this->context);
foreach ($generator as $_) {
}
$this->assertEquals(true, $generator->getReturn());
}
/**
* Helper method to set up and do scanning
*
* @param IUser|null $contextUser Optional user to scan for. If not given, images for all users will be scanned.
*/
private function doMissingImageScan($contextUser = null) {
// Reset config that full scan is done, to make sure we are scanning again
$this->config->setUserValue($this->user->getUID(), 'facerecognition', AddMissingImagesTask::FULL_IMAGE_SCAN_DONE_KEY, 'false');
$imageMapper = $this->container->query('OCA\FaceRecognition\Db\ImageMapper');
$fileService = $this->container->query('OCA\FaceRecognition\Service\FileService');
$settingsService = $this->container->query('OCA\FaceRecognition\Service\SettingsService');
$addMissingImagesTask = new AddMissingImagesTask($imageMapper, $fileService, $settingsService);
// Set user for which to do scanning, if any
$this->context->user = $contextUser;
// Since this task returns generator, iterate until it is done
$generator = $addMissingImagesTask->execute($this->context);
foreach ($generator as $_) {
}
$this->assertEquals(true, $generator->getReturn());
}
}