Files
nuqloud-ai/tests/unit/Service/ToolConfirmationServiceTest.php

129 lines
4.2 KiB
PHP

<?php
declare(strict_types=1);
namespace OCA\EducAI\Tests\Unit\Service;
use OCA\EducAI\Db\PendingToolConfirmationMapper;
use OCA\EducAI\Service\ToolConfirmationService;
use PHPUnit\Framework\TestCase;
class ToolConfirmationServiceTest extends TestCase {
public function testDoesNotQueryStorageWithoutAffirmativeUserConfirmationMessage(): void {
$mapper = $this->createMock(PendingToolConfirmationMapper::class);
$mapper->expects($this->never())->method('findActiveForAction');
$service = new ToolConfirmationService($mapper);
$this->assertFalse($service->consume('nuqloud_files_delete', [
'path' => 'private.txt',
], [
'user_id' => 'alice',
'bot_id' => 7,
'room_token' => 'room-a',
'user_message' => 'not yet',
]));
}
public function testConsumesMatchingPendingActionAfterShortAffirmativeReply(): void {
$confirmation = new PendingToolConfirmation();
$confirmation->setId(42);
$mapper = $this->createMock(PendingToolConfirmationMapper::class);
$mapper->expects($this->once())
->method('findActiveForAction')
->with(
'alice',
7,
'room-a',
'nuqloud_talk_create_conversation',
hash('sha256', '{"name":"Project room","visibility":"private"}'),
101,
$this->isType('int')
)
->willReturn($confirmation);
$mapper->expects($this->once())->method('claim')->with($confirmation, $this->isType('int'))->willReturn(true);
$service = new ToolConfirmationService($mapper);
$this->assertTrue($service->consume('nuqloud_talk_create_conversation', [
'name' => 'Project room',
'visibility' => 'private',
], [
'user_id' => 'alice',
'bot_id' => 7,
'room_token' => 'room-a',
'talk_message_id' => 101,
'user_message' => 'yes create',
]));
}
public function testConsumesNaturalAffirmativeReply(): void {
$confirmation = new PendingToolConfirmation();
$confirmation->setId(42);
$mapper = $this->createMock(PendingToolConfirmationMapper::class);
$mapper->expects($this->once())->method('findActiveForAction')->willReturn($confirmation);
$mapper->expects($this->once())->method('claim')->with($confirmation, $this->isType('int'))->willReturn(true);
$service = new ToolConfirmationService($mapper);
$this->assertTrue($service->consume('nuqloud_files_delete', [
'path' => 'private.txt',
], [
'user_id' => 'alice',
'bot_id' => 7,
'room_token' => 'room-a',
'talk_message_id' => 101,
'user_message' => 'Affirmative, please delete it.',
]));
}
public function testRejectsContradictoryAffirmativeReply(): void {
$mapper = $this->createMock(PendingToolConfirmationMapper::class);
$mapper->expects($this->never())->method('findActiveForAction');
$service = new ToolConfirmationService($mapper);
$this->assertFalse($service->consume('nuqloud_files_delete', [
'path' => 'private.txt',
], [
'user_id' => 'alice',
'bot_id' => 7,
'room_token' => 'room-a',
'talk_message_id' => 101,
'user_message' => "Yes, but don't delete it.",
]));
}
public function testDoesNotConsumeConfirmationWithoutTalkMessageId(): void {
$mapper = $this->createMock(PendingToolConfirmationMapper::class);
$mapper->expects($this->never())->method('claim');
$service = new ToolConfirmationService($mapper);
$this->assertFalse($service->consume('nuqloud_talk_create_conversation', [
'name' => 'Project room',
], [
'user_id' => 'alice',
'bot_id' => 7,
'room_token' => 'room-a',
'user_message' => 'yes',
]));
}
public function testRequestStoresOnlyActionHashAndBoundIdentity(): void {
$mapper = $this->createMock(PendingToolConfirmationMapper::class);
$mapper->expects($this->once())->method('insert')->with($this->callback(function ($confirmation): bool {
return $confirmation->getUserId() === 'alice'
&& $confirmation->getBotId() === 7
&& $confirmation->getRoomToken() === 'room-a'
&& $confirmation->getToolName() === 'nuqloud_files_delete'
&& strlen($confirmation->getArgumentsHash()) === 64
&& $confirmation->getExpiresAt() > time();
}));
$service = new ToolConfirmationService($mapper);
$result = $service->request('nuqloud_files_delete', ['path' => 'private.txt'], [
'user_id' => 'alice',
'bot_id' => 7,
'room_token' => 'room-a',
]);
$this->assertSame(600, $result['expires_in_seconds']);
}
}