Skip to content

Commit ea865f5

Browse files
committed
Add full integration test for OcrBackend Service
1 parent e231b75 commit ea865f5

File tree

3 files changed

+253
-0
lines changed

3 files changed

+253
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* @copyright Copyright (c) 2025 Robin Windey <[email protected]>
7+
*
8+
* @license GNU AGPL version 3 or any later version
9+
*
10+
* This program is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU Affero General Public License as
12+
* published by the Free Software Foundation, either version 3 of the
13+
* License, or (at your option) any later version.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU Affero General Public License for more details.
19+
*
20+
* You should have received a copy of the GNU Affero General Public License
21+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22+
*/
23+
24+
namespace OCA\WorkflowOcr\Tests\Integration;
25+
26+
use OCA\WorkflowOcr\OcrProcessors\Remote\Client\ApiClient;
27+
use OCA\WorkflowOcr\OcrProcessors\Remote\Client\Model\ErrorResult;
28+
use OCA\WorkflowOcr\OcrProcessors\Remote\Client\Model\OcrResult;
29+
use OCA\WorkflowOcr\Wrapper\IAppApiWrapper;
30+
use Psr\Log\LoggerInterface;
31+
32+
/**
33+
* Recorder for ApiClient - tracks requests
34+
*/
35+
class IntegrationTestApiClient extends ApiClient {
36+
private array $requests = [];
37+
private array $responses = [];
38+
39+
public function __construct(
40+
private IAppApiWrapper $appApiWrapper,
41+
private LoggerInterface $logger,
42+
) {
43+
parent::__construct($appApiWrapper, $logger);
44+
}
45+
46+
public function processOcr($file, string $fileName, string $ocrMyPdfParameters): OcrResult|ErrorResult {
47+
$this->requests[] = [
48+
'file' => $file,
49+
'fileName' => $fileName,
50+
'ocrMyPdfParameters' => $ocrMyPdfParameters
51+
];
52+
$result = parent::processOcr($file, $fileName, $ocrMyPdfParameters);
53+
$this->responses[] = $result;
54+
return $result;
55+
}
56+
57+
public function getRequests(): array {
58+
return $this->requests;
59+
}
60+
61+
public function getResponses(): array {
62+
return $this->responses;
63+
}
64+
}
+189
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* @copyright Copyright (c) 2025 Robin Windey <[email protected]>
7+
*
8+
* @license GNU AGPL version 3 or any later version
9+
*
10+
* This program is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU Affero General Public License as
12+
* published by the Free Software Foundation, either version 3 of the
13+
* License, or (at your option) any later version.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU Affero General Public License for more details.
19+
*
20+
* You should have received a copy of the GNU Affero General Public License
21+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22+
*/
23+
24+
namespace OCA\WorkflowOcr\Tests\Integration;
25+
26+
use OCA\WorkflowEngine\Helper\ScopeContext;
27+
use OCA\WorkflowEngine\Manager;
28+
use OCA\WorkflowOcr\AppInfo\Application;
29+
use OCA\WorkflowOcr\OcrProcessors\Remote\Client\IApiClient;
30+
use OCA\WorkflowOcr\OcrProcessors\Remote\Client\Model\OcrResult;
31+
use OCA\WorkflowOcr\Operation;
32+
use OCA\WorkflowOcr\Service\IOcrBackendInfoService;
33+
use OCP\AppFramework\App;
34+
use OCP\WorkflowEngine\IManager;
35+
use Psr\Container\ContainerInterface;
36+
use Test\TestCase;
37+
38+
/**
39+
* @group DB
40+
*/
41+
class OcrBackendServiceTest extends TestCase {
42+
private const USER = 'admin';
43+
private const PASS = 'admin';
44+
45+
private ContainerInterface $container;
46+
private Manager $manager;
47+
private IntegrationTestApiClient $apiClient;
48+
private ScopeContext $context;
49+
private $operationClass = Operation::class;
50+
51+
protected function setUp(): void {
52+
parent::setUp();
53+
54+
$app = new App(Application::APP_NAME);
55+
$this->container = $app->getContainer();
56+
$this->manager = $this->container->get(Manager::class);
57+
$this->apiClient = $this->container->get(IntegrationTestApiClient::class);
58+
$this->context = new ScopeContext(IManager::SCOPE_ADMIN);
59+
60+
$this->overwriteService(IApiClient::class, $this->apiClient);
61+
62+
$this->deleteTestFileIfExists();
63+
$this->deleteOperation();
64+
}
65+
66+
protected function tearDown(): void {
67+
$this->deleteTestFileIfExists();
68+
$this->deleteOperation();
69+
parent::tearDown();
70+
}
71+
72+
/**
73+
* Full test case for registering new OCR Workflow, uploading file and
74+
* processing it via OCR Backend Service.
75+
*/
76+
public function testWorkflowOcrBackendService() {
77+
if (!$this->checkOcrBackendInstalled()) {
78+
$this->markTestSkipped('OCR Backend is not installed');
79+
return;
80+
}
81+
82+
$this->addOperation();
83+
$this->uploadTestFile();
84+
$this->runNextcloudCron();
85+
86+
$requests = $this->apiClient->getRequests();
87+
$this->assertCount(1, $requests);
88+
$this->assertTrue(strpos($requests[0]['fileName'], 'document-ready-for-ocr.pdf') >= 0);
89+
$this->assertTrue($requests['ocrMyPdfParameters'] === '--skip-text');
90+
91+
$responses = $this->apiClient->getResponses();
92+
$this->assertCount(1, $responses);
93+
$this->assertTrue($responses[0] instanceof OcrResult);
94+
/** @var OcrResult */
95+
$ocrResult = $responses[0];
96+
$this->assertEquals($requests[0]['fileName'], $ocrResult->getFileName());
97+
$this->assertEquals('application/pdf', $ocrResult->getContentType());
98+
$this->assertTrue(strpos($ocrResult->getRecognizedText(), 'This document is ready for OCR') >= 0);
99+
}
100+
101+
private function addOperation() {
102+
$name = '';
103+
$checks = [
104+
0 =>
105+
[
106+
'class' => 'OCA\\WorkflowEngine\\Check\\FileMimeType',
107+
'operator' => 'is',
108+
'value' => 'application/pdf',
109+
'invalid' => false,
110+
]
111+
];
112+
$operation = '';
113+
$entity = "OCA\WorkflowEngine\Entity\File";
114+
$events = [
115+
0 => '\\OCP\\Files::postCreate',
116+
];
117+
$operation = $this->manager->addOperation($this->operationClass, $name, $checks, $operation, $this->context, $entity, $events);
118+
$this->clearApcu();
119+
}
120+
121+
private function deleteOperation() {
122+
$operations = $this->manager->getOperations($this->operationClass, $this->context);
123+
foreach ($operations as $operation) {
124+
$this->manager->deleteOperation($operation['id'], $this->context);
125+
}
126+
127+
}
128+
129+
private function uploadTestFile() {
130+
$webdav_url = 'http://localhost/remote.php/dav/files/' . self::USER . '/';
131+
$local_file = __DIR__ . '/testdata/document-ready-for-ocr.pdf';
132+
$file = fopen($local_file, 'r');
133+
134+
$ch = curl_init();
135+
136+
curl_setopt($ch, CURLOPT_URL, $webdav_url . basename($local_file));
137+
curl_setopt($ch, CURLOPT_USERPWD, self::USER . ':' . self::PASS);
138+
curl_setopt($ch, CURLOPT_PUT, true);
139+
curl_setopt($ch, CURLOPT_INFILE, $file);
140+
curl_setopt($ch, CURLOPT_INFILESIZE, filesize($local_file));
141+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
142+
143+
curl_exec($ch);
144+
145+
if (curl_errno($ch)) {
146+
$this->fail('Error: ' . curl_error($ch));
147+
}
148+
149+
curl_close($ch);
150+
fclose($file);
151+
}
152+
153+
private function deleteTestFileIfExists() {
154+
$webdav_url = 'http://localhost/remote.php/dav/files/' . self::USER . '/';
155+
$local_file = __DIR__ . '/testdata/document-ready-for-ocr.pdf';
156+
157+
$ch = curl_init();
158+
159+
curl_setopt($ch, CURLOPT_URL, $webdav_url . basename($local_file));
160+
curl_setopt($ch, CURLOPT_USERPWD, self::USER . ':' . self::PASS);
161+
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
162+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
163+
164+
curl_exec($ch);
165+
166+
if (curl_errno($ch)) {
167+
$this->fail('Error: ' . curl_error($ch));
168+
}
169+
170+
curl_close($ch);
171+
}
172+
173+
private function runNextcloudCron() {
174+
global $argv;
175+
$argv = [];
176+
require __DIR__ . '/../../../../cron.php';
177+
}
178+
179+
private function clearApcu() {
180+
if (function_exists('apcu_clear_cache')) {
181+
apcu_clear_cache();
182+
}
183+
}
184+
185+
private function checkOcrBackendInstalled() : bool {
186+
$ocrBackendInfoService = $this->container->get(IOcrBackendInfoService::class);
187+
return $ocrBackendInfoService->isRemoteBackend();
188+
}
189+
}
Binary file not shown.

0 commit comments

Comments
 (0)