mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
Merge pull request #52050 from nextcloud/fix/noid/taskprocessing-appapi
fix(taskprocessing): use the event for AppAPI to get list of AI providers
This commit is contained in:
commit
0a474e5ccd
5 changed files with 434 additions and 2 deletions
|
|
@ -816,6 +816,7 @@ return array(
|
|||
'OCP\\Talk\\ITalkBackend' => $baseDir . '/lib/public/Talk/ITalkBackend.php',
|
||||
'OCP\\TaskProcessing\\EShapeType' => $baseDir . '/lib/public/TaskProcessing/EShapeType.php',
|
||||
'OCP\\TaskProcessing\\Events\\AbstractTaskProcessingEvent' => $baseDir . '/lib/public/TaskProcessing/Events/AbstractTaskProcessingEvent.php',
|
||||
'OCP\\TaskProcessing\\Events\\GetTaskProcessingProvidersEvent' => $baseDir . '/lib/public/TaskProcessing/Events/GetTaskProcessingProvidersEvent.php',
|
||||
'OCP\\TaskProcessing\\Events\\TaskFailedEvent' => $baseDir . '/lib/public/TaskProcessing/Events/TaskFailedEvent.php',
|
||||
'OCP\\TaskProcessing\\Events\\TaskSuccessfulEvent' => $baseDir . '/lib/public/TaskProcessing/Events/TaskSuccessfulEvent.php',
|
||||
'OCP\\TaskProcessing\\Exception\\Exception' => $baseDir . '/lib/public/TaskProcessing/Exception/Exception.php',
|
||||
|
|
|
|||
|
|
@ -865,6 +865,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OCP\\Talk\\ITalkBackend' => __DIR__ . '/../../..' . '/lib/public/Talk/ITalkBackend.php',
|
||||
'OCP\\TaskProcessing\\EShapeType' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/EShapeType.php',
|
||||
'OCP\\TaskProcessing\\Events\\AbstractTaskProcessingEvent' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/Events/AbstractTaskProcessingEvent.php',
|
||||
'OCP\\TaskProcessing\\Events\\GetTaskProcessingProvidersEvent' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/Events/GetTaskProcessingProvidersEvent.php',
|
||||
'OCP\\TaskProcessing\\Events\\TaskFailedEvent' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/Events/TaskFailedEvent.php',
|
||||
'OCP\\TaskProcessing\\Events\\TaskSuccessfulEvent' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/Events/TaskSuccessfulEvent.php',
|
||||
'OCP\\TaskProcessing\\Exception\\Exception' => __DIR__ . '/../../..' . '/lib/public/TaskProcessing/Exception/Exception.php',
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ use OCP\Lock\LockedException;
|
|||
use OCP\SpeechToText\ISpeechToTextProvider;
|
||||
use OCP\SpeechToText\ISpeechToTextProviderWithId;
|
||||
use OCP\TaskProcessing\EShapeType;
|
||||
use OCP\TaskProcessing\Events\GetTaskProcessingProvidersEvent;
|
||||
use OCP\TaskProcessing\Events\TaskFailedEvent;
|
||||
use OCP\TaskProcessing\Events\TaskSuccessfulEvent;
|
||||
use OCP\TaskProcessing\Exception\NotFoundException;
|
||||
|
|
@ -81,8 +82,13 @@ class Manager implements IManager {
|
|||
private IAppData $appData;
|
||||
private ?array $preferences = null;
|
||||
private ?array $providersById = null;
|
||||
|
||||
/** @var ITaskType[]|null */
|
||||
private ?array $taskTypes = null;
|
||||
private ICache $distributedCache;
|
||||
|
||||
private ?GetTaskProcessingProvidersEvent $eventResult = null;
|
||||
|
||||
public function __construct(
|
||||
private IConfig $config,
|
||||
private Coordinator $coordinator,
|
||||
|
|
@ -488,6 +494,20 @@ class Manager implements IManager {
|
|||
return $newProviders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the event to collect external providers and task types.
|
||||
* Caches the result within the request.
|
||||
*/
|
||||
private function dispatchGetProvidersEvent(): GetTaskProcessingProvidersEvent {
|
||||
if ($this->eventResult !== null) {
|
||||
return $this->eventResult;
|
||||
}
|
||||
|
||||
$this->eventResult = new GetTaskProcessingProvidersEvent();
|
||||
$this->dispatcher->dispatchTyped($this->eventResult);
|
||||
return $this->eventResult ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IProvider[]
|
||||
*/
|
||||
|
|
@ -516,6 +536,16 @@ class Manager implements IManager {
|
|||
}
|
||||
}
|
||||
|
||||
$event = $this->dispatchGetProvidersEvent();
|
||||
$externalProviders = $event->getProviders();
|
||||
foreach ($externalProviders as $provider) {
|
||||
if (!isset($providers[$provider->getId()])) {
|
||||
$providers[$provider->getId()] = $provider;
|
||||
} else {
|
||||
$this->logger->info('Skipping external task processing provider with ID ' . $provider->getId() . ' because a local provider with the same ID already exists.');
|
||||
}
|
||||
}
|
||||
|
||||
$providers += $this->_getTextProcessingProviders() + $this->_getTextToImageProviders() + $this->_getSpeechToTextProviders();
|
||||
|
||||
return $providers;
|
||||
|
|
@ -531,6 +561,10 @@ class Manager implements IManager {
|
|||
return [];
|
||||
}
|
||||
|
||||
if ($this->taskTypes !== null) {
|
||||
return $this->taskTypes;
|
||||
}
|
||||
|
||||
// Default task types
|
||||
$taskTypes = [
|
||||
\OCP\TaskProcessing\TaskTypes\TextToText::ID => \OCP\Server::get(\OCP\TaskProcessing\TaskTypes\TextToText::class),
|
||||
|
|
@ -568,9 +602,19 @@ class Manager implements IManager {
|
|||
}
|
||||
}
|
||||
|
||||
$event = $this->dispatchGetProvidersEvent();
|
||||
$externalTaskTypes = $event->getTaskTypes();
|
||||
foreach ($externalTaskTypes as $taskType) {
|
||||
if (isset($taskTypes[$taskType->getId()])) {
|
||||
$this->logger->warning('External task processing task type is using ID ' . $taskType->getId() . ' which is already used by a locally registered task type (' . get_class($taskTypes[$taskType->getId()]) . ')');
|
||||
}
|
||||
$taskTypes[$taskType->getId()] = $taskType;
|
||||
}
|
||||
|
||||
$taskTypes += $this->_getTextProcessingTaskTypes();
|
||||
|
||||
return $taskTypes;
|
||||
$this->taskTypes = $taskTypes;
|
||||
return $this->taskTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\TaskProcessing\Events;
|
||||
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\TaskProcessing\IProvider;
|
||||
use OCP\TaskProcessing\ITaskType;
|
||||
|
||||
/**
|
||||
* Event dispatched by the server to collect Task Processing Providers
|
||||
* and custom Task Types from listeners (like AppAPI).
|
||||
*
|
||||
* Listeners should add their providers and task types using the
|
||||
* addProvider() and addTaskType() methods.
|
||||
*
|
||||
* @since 32.0.0
|
||||
*/
|
||||
class GetTaskProcessingProvidersEvent extends Event {
|
||||
/** @var IProvider[] */
|
||||
private array $providers = [];
|
||||
|
||||
/** @var ITaskType[] */
|
||||
private array $taskTypes = [];
|
||||
|
||||
/**
|
||||
* Add a Task Processing Provider.
|
||||
*
|
||||
* @param IProvider $provider The provider instance to add.
|
||||
* @since 32.0.0
|
||||
*/
|
||||
public function addProvider(IProvider $provider): void {
|
||||
$this->providers[] = $provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all collected Task Processing Providers.
|
||||
*
|
||||
* @return IProvider[]
|
||||
* @since 32.0.0
|
||||
*/
|
||||
public function getProviders(): array {
|
||||
return $this->providers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom Task Processing Task Type.
|
||||
*
|
||||
* @param ITaskType $taskType The task type instance to add.
|
||||
* @since 32.0.0
|
||||
*/
|
||||
public function addTaskType(ITaskType $taskType): void {
|
||||
$this->taskTypes[] = $taskType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all collected custom Task Processing Task Types.
|
||||
*
|
||||
* @return ITaskType[]
|
||||
* @since 32.0.0
|
||||
*/
|
||||
public function getTaskTypes(): array {
|
||||
return $this->taskTypes;
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ use OCP\IServerContainer;
|
|||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\TaskProcessing\EShapeType;
|
||||
use OCP\TaskProcessing\Events\GetTaskProcessingProvidersEvent;
|
||||
use OCP\TaskProcessing\Events\TaskFailedEvent;
|
||||
use OCP\TaskProcessing\Events\TaskSuccessfulEvent;
|
||||
use OCP\TaskProcessing\Exception\NotFoundException;
|
||||
|
|
@ -131,8 +132,10 @@ class AsyncProvider implements IProvider {
|
|||
}
|
||||
|
||||
class SuccessfulSyncProvider implements IProvider, ISynchronousProvider {
|
||||
public const ID = 'test:sync:success';
|
||||
|
||||
public function getId(): string {
|
||||
return 'test:sync:success';
|
||||
return self::ID;
|
||||
}
|
||||
|
||||
public function getName(): string {
|
||||
|
|
@ -385,6 +388,132 @@ class FailingTextToImageProvider implements \OCP\TextToImage\IProvider {
|
|||
}
|
||||
}
|
||||
|
||||
class ExternalProvider implements IProvider {
|
||||
public const ID = 'event:external:provider';
|
||||
public const TASK_TYPE_ID = 'event:external:tasktype';
|
||||
|
||||
public function getId(): string {
|
||||
return self::ID;
|
||||
}
|
||||
public function getName(): string {
|
||||
return 'External Provider via Event';
|
||||
}
|
||||
public function getTaskTypeId(): string {
|
||||
return self::TASK_TYPE_ID;
|
||||
}
|
||||
public function getExpectedRuntime(): int {
|
||||
return 5;
|
||||
}
|
||||
public function getOptionalInputShape(): array {
|
||||
return [];
|
||||
}
|
||||
public function getOptionalOutputShape(): array {
|
||||
return [];
|
||||
}
|
||||
public function getInputShapeEnumValues(): array {
|
||||
return [];
|
||||
}
|
||||
public function getInputShapeDefaults(): array {
|
||||
return [];
|
||||
}
|
||||
public function getOptionalInputShapeEnumValues(): array {
|
||||
return [];
|
||||
}
|
||||
public function getOptionalInputShapeDefaults(): array {
|
||||
return [];
|
||||
}
|
||||
public function getOutputShapeEnumValues(): array {
|
||||
return [];
|
||||
}
|
||||
public function getOptionalOutputShapeEnumValues(): array {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
class ConflictingExternalProvider implements IProvider {
|
||||
// Same ID as SuccessfulSyncProvider
|
||||
public const ID = 'test:sync:success';
|
||||
public const TASK_TYPE_ID = 'event:external:tasktype'; // Can be different task type
|
||||
|
||||
public function getId(): string {
|
||||
return self::ID;
|
||||
}
|
||||
public function getName(): string {
|
||||
return 'Conflicting External Provider';
|
||||
}
|
||||
public function getTaskTypeId(): string {
|
||||
return self::TASK_TYPE_ID;
|
||||
}
|
||||
public function getExpectedRuntime(): int {
|
||||
return 50;
|
||||
}
|
||||
public function getOptionalInputShape(): array {
|
||||
return [];
|
||||
}
|
||||
public function getOptionalOutputShape(): array {
|
||||
return [];
|
||||
}
|
||||
public function getInputShapeEnumValues(): array {
|
||||
return [];
|
||||
}
|
||||
public function getInputShapeDefaults(): array {
|
||||
return [];
|
||||
}
|
||||
public function getOptionalInputShapeEnumValues(): array {
|
||||
return [];
|
||||
}
|
||||
public function getOptionalInputShapeDefaults(): array {
|
||||
return [];
|
||||
}
|
||||
public function getOutputShapeEnumValues(): array {
|
||||
return [];
|
||||
}
|
||||
public function getOptionalOutputShapeEnumValues(): array {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
class ExternalTaskType implements ITaskType {
|
||||
public const ID = 'event:external:tasktype';
|
||||
|
||||
public function getId(): string {
|
||||
return self::ID;
|
||||
}
|
||||
public function getName(): string {
|
||||
return 'External Task Type via Event';
|
||||
}
|
||||
public function getDescription(): string {
|
||||
return 'A task type added via event';
|
||||
}
|
||||
public function getInputShape(): array {
|
||||
return ['external_input' => new ShapeDescriptor('Ext In', '', EShapeType::Text)];
|
||||
}
|
||||
public function getOutputShape(): array {
|
||||
return ['external_output' => new ShapeDescriptor('Ext Out', '', EShapeType::Text)];
|
||||
}
|
||||
}
|
||||
|
||||
class ConflictingExternalTaskType implements ITaskType {
|
||||
// Same ID as built-in TextToText
|
||||
public const ID = TextToText::ID;
|
||||
|
||||
public function getId(): string {
|
||||
return self::ID;
|
||||
}
|
||||
public function getName(): string {
|
||||
return 'Conflicting External Task Type';
|
||||
}
|
||||
public function getDescription(): string {
|
||||
return 'Overrides built-in TextToText';
|
||||
}
|
||||
public function getInputShape(): array {
|
||||
return ['override_input' => new ShapeDescriptor('Override In', '', EShapeType::Number)];
|
||||
}
|
||||
public function getOutputShape(): array {
|
||||
return ['override_output' => new ShapeDescriptor('Override Out', '', EShapeType::Number)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
*/
|
||||
|
|
@ -416,6 +545,10 @@ class TaskProcessingTest extends \Test\TestCase {
|
|||
FailingTextProcessingSummaryProvider::class => new FailingTextProcessingSummaryProvider(),
|
||||
SuccessfulTextToImageProvider::class => new SuccessfulTextToImageProvider(),
|
||||
FailingTextToImageProvider::class => new FailingTextToImageProvider(),
|
||||
ExternalProvider::class => new ExternalProvider(),
|
||||
ConflictingExternalProvider::class => new ConflictingExternalProvider(),
|
||||
ExternalTaskType::class => new ExternalTaskType(),
|
||||
ConflictingExternalTaskType::class => new ConflictingExternalTaskType(),
|
||||
];
|
||||
|
||||
$userManager = \OCP\Server::get(IUserManager::class);
|
||||
|
|
@ -447,6 +580,7 @@ class TaskProcessingTest extends \Test\TestCase {
|
|||
});
|
||||
|
||||
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
|
||||
$this->configureEventDispatcherMock();
|
||||
|
||||
$text2imageManager = new \OC\TextToImage\Manager(
|
||||
$this->serverContainer,
|
||||
|
|
@ -964,4 +1098,188 @@ class TaskProcessingTest extends \Test\TestCase {
|
|||
self::assertEquals('ERROR', $task->getErrorMessage());
|
||||
self::assertTrue($this->providers[FailingTextToImageProvider::class]->ran);
|
||||
}
|
||||
|
||||
public function testMergeProvidersLocalAndEvent() {
|
||||
// Arrange: Local provider registered, DIFFERENT external provider via event
|
||||
$this->registrationContext->expects($this->any())->method('getTaskProcessingProviders')->willReturn([
|
||||
new ServiceRegistration('test', SuccessfulSyncProvider::class)
|
||||
]);
|
||||
$this->registrationContext->expects($this->any())->method('getTextProcessingProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getTextToImageProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getSpeechToTextProviders')->willReturn([]);
|
||||
|
||||
$externalProvider = new ExternalProvider(); // ID = 'event:external:provider'
|
||||
$this->configureEventDispatcherMock(providersToAdd: [$externalProvider]);
|
||||
$this->manager = $this->createManagerInstance();
|
||||
|
||||
// Act
|
||||
$providers = $this->manager->getProviders();
|
||||
|
||||
// Assert: Both providers should be present
|
||||
self::assertArrayHasKey(SuccessfulSyncProvider::ID, $providers);
|
||||
self::assertInstanceOf(SuccessfulSyncProvider::class, $providers[SuccessfulSyncProvider::ID]);
|
||||
self::assertArrayHasKey(ExternalProvider::ID, $providers);
|
||||
self::assertInstanceOf(ExternalProvider::class, $providers[ExternalProvider::ID]);
|
||||
self::assertCount(2, $providers);
|
||||
}
|
||||
|
||||
public function testGetProvidersIncludesExternalViaEvent() {
|
||||
// Arrange: No local providers, one external provider via event
|
||||
$this->registrationContext->expects($this->any())->method('getTaskProcessingProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getTextProcessingProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getTextToImageProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getSpeechToTextProviders')->willReturn([]);
|
||||
|
||||
|
||||
$externalProvider = new ExternalProvider();
|
||||
$this->configureEventDispatcherMock(providersToAdd: [$externalProvider]);
|
||||
$this->manager = $this->createManagerInstance(); // Create manager with configured mocks
|
||||
|
||||
// Act
|
||||
$providers = $this->manager->getProviders(); // Returns ID-indexed array
|
||||
|
||||
// Assert
|
||||
self::assertArrayHasKey(ExternalProvider::ID, $providers);
|
||||
self::assertInstanceOf(ExternalProvider::class, $providers[ExternalProvider::ID]);
|
||||
self::assertCount(1, $providers);
|
||||
self::assertTrue($this->manager->hasProviders());
|
||||
}
|
||||
|
||||
public function testGetAvailableTaskTypesIncludesExternalViaEvent() {
|
||||
// Arrange: No local types/providers, one external type and provider via event
|
||||
$this->registrationContext->expects($this->any())->method('getTaskProcessingProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getTaskProcessingTaskTypes')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getTextProcessingProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getTextToImageProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getSpeechToTextProviders')->willReturn([]);
|
||||
|
||||
$externalProvider = new ExternalProvider(); // Provides ExternalTaskType
|
||||
$externalTaskType = new ExternalTaskType();
|
||||
$this->configureEventDispatcherMock(
|
||||
providersToAdd: [$externalProvider],
|
||||
taskTypesToAdd: [$externalTaskType]
|
||||
);
|
||||
$this->manager = $this->createManagerInstance();
|
||||
|
||||
// Act
|
||||
$availableTypes = $this->manager->getAvailableTaskTypes();
|
||||
|
||||
// Assert
|
||||
self::assertArrayHasKey(ExternalTaskType::ID, $availableTypes);
|
||||
self::assertEquals(ExternalTaskType::ID, $externalProvider->getTaskTypeId(), 'Test Sanity: Provider must handle the Task Type');
|
||||
self::assertEquals('External Task Type via Event', $availableTypes[ExternalTaskType::ID]['name']);
|
||||
// Check if shapes match the external type/provider
|
||||
self::assertArrayHasKey('external_input', $availableTypes[ExternalTaskType::ID]['inputShape']);
|
||||
self::assertArrayHasKey('external_output', $availableTypes[ExternalTaskType::ID]['outputShape']);
|
||||
self::assertEmpty($availableTypes[ExternalTaskType::ID]['optionalInputShape']); // From ExternalProvider
|
||||
}
|
||||
|
||||
public function testLocalProviderWinsConflictWithEvent() {
|
||||
// Arrange: Local provider registered, conflicting external provider via event
|
||||
$this->registrationContext->expects($this->any())->method('getTaskProcessingProviders')->willReturn([
|
||||
new ServiceRegistration('test', SuccessfulSyncProvider::class)
|
||||
]);
|
||||
$this->registrationContext->expects($this->any())->method('getTextProcessingProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getTextToImageProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getSpeechToTextProviders')->willReturn([]);
|
||||
|
||||
$conflictingExternalProvider = new ConflictingExternalProvider(); // ID = 'test:sync:success'
|
||||
$this->configureEventDispatcherMock(providersToAdd: [$conflictingExternalProvider]);
|
||||
$this->manager = $this->createManagerInstance();
|
||||
|
||||
// Act
|
||||
$providers = $this->manager->getProviders();
|
||||
|
||||
// Assert: Only the local provider should be present for the conflicting ID
|
||||
self::assertArrayHasKey(SuccessfulSyncProvider::ID, $providers);
|
||||
self::assertInstanceOf(SuccessfulSyncProvider::class, $providers[SuccessfulSyncProvider::ID]);
|
||||
self::assertCount(1, $providers); // Ensure no extra provider was added
|
||||
}
|
||||
|
||||
public function testMergeTaskTypesLocalAndEvent() {
|
||||
// Arrange: Local type registered, DIFFERENT external type via event
|
||||
$this->registrationContext->expects($this->any())->method('getTaskProcessingProviders')->willReturn([
|
||||
new ServiceRegistration('test', AsyncProvider::class)
|
||||
]);
|
||||
$this->registrationContext->expects($this->any())->method('getTaskProcessingTaskTypes')->willReturn([
|
||||
new ServiceRegistration('test', AudioToImage::class)
|
||||
]);
|
||||
$this->registrationContext->expects($this->any())->method('getTextProcessingProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getTextToImageProviders')->willReturn([]);
|
||||
$this->registrationContext->expects($this->any())->method('getSpeechToTextProviders')->willReturn([]);
|
||||
|
||||
$externalTaskType = new ExternalTaskType(); // ID = 'event:external:tasktype'
|
||||
$externalProvider = new ExternalProvider(); // Handles 'event:external:tasktype'
|
||||
$this->configureEventDispatcherMock(
|
||||
providersToAdd: [$externalProvider],
|
||||
taskTypesToAdd: [$externalTaskType]
|
||||
);
|
||||
$this->manager = $this->createManagerInstance();
|
||||
|
||||
// Act
|
||||
$availableTypes = $this->manager->getAvailableTaskTypes();
|
||||
|
||||
// Assert: Both task types should be available
|
||||
self::assertArrayHasKey(AudioToImage::ID, $availableTypes);
|
||||
self::assertEquals(AudioToImage::class, $availableTypes[AudioToImage::ID]['name']);
|
||||
|
||||
self::assertArrayHasKey(ExternalTaskType::ID, $availableTypes);
|
||||
self::assertEquals('External Task Type via Event', $availableTypes[ExternalTaskType::ID]['name']);
|
||||
|
||||
self::assertCount(2, $availableTypes);
|
||||
}
|
||||
|
||||
private function createManagerInstance(): Manager {
|
||||
// Clear potentially cached config values if needed
|
||||
$this->config->deleteAppValue('core', 'ai.taskprocessing_type_preferences');
|
||||
|
||||
// Re-create Text2ImageManager if its state matters or mocks change
|
||||
$text2imageManager = new \OC\TextToImage\Manager(
|
||||
$this->serverContainer,
|
||||
$this->coordinator,
|
||||
\OC::$server->get(LoggerInterface::class),
|
||||
$this->jobList,
|
||||
\OC::$server->get(\OC\TextToImage\Db\TaskMapper::class),
|
||||
$this->config, // Use the shared config mock
|
||||
\OC::$server->get(IAppDataFactory::class),
|
||||
);
|
||||
|
||||
return new Manager(
|
||||
$this->config,
|
||||
$this->coordinator,
|
||||
$this->serverContainer,
|
||||
\OC::$server->get(LoggerInterface::class),
|
||||
$this->taskMapper,
|
||||
$this->jobList,
|
||||
$this->eventDispatcher, // Use the potentially reconfigured mock
|
||||
\OC::$server->get(IAppDataFactory::class),
|
||||
$this->rootFolder,
|
||||
$text2imageManager,
|
||||
$this->userMountCache,
|
||||
\OC::$server->get(IClientService::class),
|
||||
\OC::$server->get(IAppManager::class),
|
||||
\OC::$server->get(ICacheFactory::class),
|
||||
);
|
||||
}
|
||||
|
||||
private function configureEventDispatcherMock(
|
||||
array $providersToAdd = [],
|
||||
array $taskTypesToAdd = [],
|
||||
?int $expectedCalls = null,
|
||||
): void {
|
||||
$dispatchExpectation = $expectedCalls === null ? $this->any() : $this->exactly($expectedCalls);
|
||||
|
||||
$this->eventDispatcher->expects($dispatchExpectation)
|
||||
->method('dispatchTyped')
|
||||
->willReturnCallback(function (object $event) use ($providersToAdd, $taskTypesToAdd) {
|
||||
if ($event instanceof GetTaskProcessingProvidersEvent) {
|
||||
foreach ($providersToAdd as $providerInstance) {
|
||||
$event->addProvider($providerInstance);
|
||||
}
|
||||
foreach ($taskTypesToAdd as $taskTypeInstance) {
|
||||
$event->addTaskType($taskTypeInstance);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue