From 0ca353f76ce89c7b3bc9ad5c8c2ff3dbc43fa62b Mon Sep 17 00:00:00 2001 From: Robin Windey Date: Mon, 3 Feb 2025 20:53:01 +0000 Subject: [PATCH] Add full integration test for OcrBackend Service --- .../Integration/IntegrationTestApiClient.php | 64 ++++++ tests/Integration/OcrBackendServiceTest.php | 189 ++++++++++++++++++ .../testdata/document-ready-for-ocr.pdf | Bin 0 -> 7844 bytes 3 files changed, 253 insertions(+) create mode 100644 tests/Integration/IntegrationTestApiClient.php create mode 100644 tests/Integration/OcrBackendServiceTest.php create mode 100644 tests/Integration/testdata/document-ready-for-ocr.pdf diff --git a/tests/Integration/IntegrationTestApiClient.php b/tests/Integration/IntegrationTestApiClient.php new file mode 100644 index 0000000..9a8804d --- /dev/null +++ b/tests/Integration/IntegrationTestApiClient.php @@ -0,0 +1,64 @@ + + * + * @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 . + */ + +namespace OCA\WorkflowOcr\Tests\Integration; + +use OCA\WorkflowOcr\OcrProcessors\Remote\Client\ApiClient; +use OCA\WorkflowOcr\OcrProcessors\Remote\Client\Model\ErrorResult; +use OCA\WorkflowOcr\OcrProcessors\Remote\Client\Model\OcrResult; +use OCA\WorkflowOcr\Wrapper\IAppApiWrapper; +use Psr\Log\LoggerInterface; + +/** + * Recorder for ApiClient - tracks requests + */ +class IntegrationTestApiClient extends ApiClient { + private array $requests = []; + private array $responses = []; + + public function __construct( + private IAppApiWrapper $appApiWrapper, + private LoggerInterface $logger, + ) { + parent::__construct($appApiWrapper, $logger); + } + + public function processOcr($file, string $fileName, string $ocrMyPdfParameters): OcrResult|ErrorResult { + $this->requests[] = [ + 'file' => $file, + 'fileName' => $fileName, + 'ocrMyPdfParameters' => $ocrMyPdfParameters + ]; + $result = parent::processOcr($file, $fileName, $ocrMyPdfParameters); + $this->responses[] = $result; + return $result; + } + + public function getRequests(): array { + return $this->requests; + } + + public function getResponses(): array { + return $this->responses; + } +} diff --git a/tests/Integration/OcrBackendServiceTest.php b/tests/Integration/OcrBackendServiceTest.php new file mode 100644 index 0000000..8c5272a --- /dev/null +++ b/tests/Integration/OcrBackendServiceTest.php @@ -0,0 +1,189 @@ + + * + * @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 . + */ + +namespace OCA\WorkflowOcr\Tests\Integration; + +use OCA\WorkflowEngine\Helper\ScopeContext; +use OCA\WorkflowEngine\Manager; +use OCA\WorkflowOcr\AppInfo\Application; +use OCA\WorkflowOcr\OcrProcessors\Remote\Client\IApiClient; +use OCA\WorkflowOcr\OcrProcessors\Remote\Client\Model\OcrResult; +use OCA\WorkflowOcr\Operation; +use OCA\WorkflowOcr\Service\IOcrBackendInfoService; +use OCP\AppFramework\App; +use OCP\WorkflowEngine\IManager; +use Psr\Container\ContainerInterface; +use Test\TestCase; + +/** + * @group DB + */ +class OcrBackendServiceTest extends TestCase { + private const USER = 'admin'; + private const PASS = 'admin'; + + private ContainerInterface $container; + private Manager $manager; + private IntegrationTestApiClient $apiClient; + private ScopeContext $context; + private $operationClass = Operation::class; + + protected function setUp(): void { + parent::setUp(); + + $app = new App(Application::APP_NAME); + $this->container = $app->getContainer(); + $this->manager = $this->container->get(Manager::class); + $this->apiClient = $this->container->get(IntegrationTestApiClient::class); + $this->context = new ScopeContext(IManager::SCOPE_ADMIN); + + $this->overwriteService(IApiClient::class, $this->apiClient); + + $this->deleteTestFileIfExists(); + $this->deleteOperation(); + } + + protected function tearDown(): void { + $this->deleteTestFileIfExists(); + $this->deleteOperation(); + parent::tearDown(); + } + + /** + * Full test case for registering new OCR Workflow, uploading file and + * processing it via OCR Backend Service. + */ + public function testWorkflowOcrBackendService() { + if (!$this->checkOcrBackendInstalled()) { + $this->markTestSkipped('OCR Backend is not installed'); + return; + } + + $this->addOperation(); + $this->uploadTestFile(); + $this->runNextcloudCron(); + + $requests = $this->apiClient->getRequests(); + $this->assertCount(1, $requests); + $this->assertTrue(strpos($requests[0]['fileName'], 'document-ready-for-ocr.pdf') >= 0); + $this->assertTrue($requests['ocrMyPdfParameters'] === '--skip-text'); + + $responses = $this->apiClient->getResponses(); + $this->assertCount(1, $responses); + $this->assertTrue($responses[0] instanceof OcrResult); + /** @var OcrResult */ + $ocrResult = $responses[0]; + $this->assertEquals($requests[0]['fileName'], $ocrResult->getFileName()); + $this->assertEquals('application/pdf', $ocrResult->getContentType()); + $this->assertTrue(strpos($ocrResult->getRecognizedText(), 'This document is ready for OCR') >= 0); + } + + private function addOperation() { + $name = ''; + $checks = [ + 0 => + [ + 'class' => 'OCA\\WorkflowEngine\\Check\\FileMimeType', + 'operator' => 'is', + 'value' => 'application/pdf', + 'invalid' => false, + ] + ]; + $operation = ''; + $entity = "OCA\WorkflowEngine\Entity\File"; + $events = [ + 0 => '\\OCP\\Files::postCreate', + ]; + $operation = $this->manager->addOperation($this->operationClass, $name, $checks, $operation, $this->context, $entity, $events); + $this->clearApcu(); + } + + private function deleteOperation() { + $operations = $this->manager->getOperations($this->operationClass, $this->context); + foreach ($operations as $operation) { + $this->manager->deleteOperation($operation['id'], $this->context); + } + + } + + private function uploadTestFile() { + $webdav_url = 'http://localhost/remote.php/dav/files/' . self::USER . '/'; + $local_file = __DIR__ . '/testdata/document-ready-for-ocr.pdf'; + $file = fopen($local_file, 'r'); + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $webdav_url . basename($local_file)); + curl_setopt($ch, CURLOPT_USERPWD, self::USER . ':' . self::PASS); + curl_setopt($ch, CURLOPT_PUT, true); + curl_setopt($ch, CURLOPT_INFILE, $file); + curl_setopt($ch, CURLOPT_INFILESIZE, filesize($local_file)); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + curl_exec($ch); + + if (curl_errno($ch)) { + $this->fail('Error: ' . curl_error($ch)); + } + + curl_close($ch); + fclose($file); + } + + private function deleteTestFileIfExists() { + $webdav_url = 'http://localhost/remote.php/dav/files/' . self::USER . '/'; + $local_file = __DIR__ . '/testdata/document-ready-for-ocr.pdf'; + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $webdav_url . basename($local_file)); + curl_setopt($ch, CURLOPT_USERPWD, self::USER . ':' . self::PASS); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + curl_exec($ch); + + if (curl_errno($ch)) { + $this->fail('Error: ' . curl_error($ch)); + } + + curl_close($ch); + } + + private function runNextcloudCron() { + global $argv; + $argv = []; + require __DIR__ . '/../../../../cron.php'; + } + + private function clearApcu() { + if (function_exists('apcu_clear_cache')) { + apcu_clear_cache(); + } + } + + private function checkOcrBackendInstalled() : bool { + $ocrBackendInfoService = $this->container->get(IOcrBackendInfoService::class); + return $ocrBackendInfoService->isRemoteBackend(); + } +} diff --git a/tests/Integration/testdata/document-ready-for-ocr.pdf b/tests/Integration/testdata/document-ready-for-ocr.pdf new file mode 100644 index 0000000000000000000000000000000000000000..702f5361ef421e625c91e5940a6df9a292b947ba GIT binary patch literal 7844 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 AJOBUy literal 0 HcmV?d00001