All checks were successful
Nextcloud Server Tests / version-consistency (push) Successful in 32s
Nextcloud Server Tests / matrix-config (push) Successful in 26s
Nextcloud Server Tests / Nextcloud stable30 / PHP 8.2 (stable30, 8.2) (push) Successful in 4m44s
Nextcloud Server Tests / Nextcloud stable31 / PHP 8.2 (stable31, 8.2) (push) Successful in 4m41s
Nextcloud Server Tests / Nextcloud stable31 / PHP 8.3 (stable31, 8.3) (push) Successful in 4m29s
Nextcloud Server Tests / Nextcloud stable32 / PHP 8.2 (stable32, 8.2) (push) Successful in 4m34s
Nextcloud Server Tests / Nextcloud stable32 / PHP 8.3 (stable32, 8.3) (push) Successful in 4m43s
Nextcloud Server Tests / Nextcloud stable33 / PHP 8.2 (stable33, 8.2) (push) Successful in 4m51s
Nextcloud Server Tests / Nextcloud stable33 / PHP 8.3 (stable33, 8.3) (push) Successful in 4m52s
Build And Publish Appstore Package / build_and_publish (push) Successful in 3m3s
278 lines
8.5 KiB
PHP
278 lines
8.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace OCA\Opsdash\Tests\Controller;
|
|
|
|
use OCA\Opsdash\Controller\NotesController;
|
|
use OCA\Opsdash\Service\NotesService;
|
|
use OCP\AppFramework\Http\DataResponse;
|
|
use OCP\AppFramework\Http;
|
|
use OCP\IRequest;
|
|
use OCP\IUser;
|
|
use OCP\IUserSession;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
class NotesControllerTest extends TestCase {
|
|
private IRequest $request;
|
|
private IUserSession $userSession;
|
|
private NotesService $notesService;
|
|
private NotesController $controller;
|
|
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
|
|
$this->request = $this->createMock(IRequest::class);
|
|
$this->request->method('getHeader')->willReturn('token');
|
|
$this->request->method('passesCSRFCheck')->willReturn(true);
|
|
$this->userSession = $this->createMock(IUserSession::class);
|
|
$this->notesService = $this->createMock(NotesService::class);
|
|
$logger = $this->createMock(LoggerInterface::class);
|
|
|
|
$this->controller = new NotesController(
|
|
'opsdash',
|
|
$this->request,
|
|
$this->userSession,
|
|
$logger,
|
|
$this->notesService,
|
|
);
|
|
}
|
|
|
|
public function testNotesRequiresUser(): void {
|
|
$this->userSession->method('getUser')->willReturn(null);
|
|
|
|
$response = $this->controller->notes();
|
|
$this->assertInstanceOf(DataResponse::class, $response);
|
|
$this->assertSame(Http::STATUS_UNAUTHORIZED, $response->getStatus());
|
|
}
|
|
|
|
public function testNotesClampsRangeAndOffset(): void {
|
|
$user = $this->createMock(IUser::class);
|
|
$user->method('getUID')->willReturn('admin');
|
|
$this->userSession->method('getUser')->willReturn($user);
|
|
|
|
$this->request->method('getParam')->willReturnMap([
|
|
['range', 'week', 'year'],
|
|
['offset', 0, 99],
|
|
]);
|
|
|
|
$this->notesService
|
|
->expects($this->once())
|
|
->method('getNotes')
|
|
->with('admin', 'week', 24)
|
|
->willReturn(['notes' => ['current' => 'ok']]);
|
|
|
|
$response = $this->controller->notes();
|
|
$this->assertSame(Http::STATUS_OK, $response->getStatus());
|
|
$this->assertSame(['ok' => true, 'notes' => ['current' => 'ok']], $response->getData());
|
|
}
|
|
|
|
public function testNotesRejectsLargeQuery(): void {
|
|
$user = $this->createMock(IUser::class);
|
|
$user->method('getUID')->willReturn('admin');
|
|
$this->userSession->method('getUser')->willReturn($user);
|
|
|
|
$previous = $_SERVER['QUERY_STRING'] ?? null;
|
|
$_SERVER['QUERY_STRING'] = str_repeat('a', 5000);
|
|
|
|
try {
|
|
$response = $this->controller->notes();
|
|
$this->assertSame(Http::STATUS_REQUEST_URI_TOO_LONG, $response->getStatus());
|
|
} finally {
|
|
if ($previous === null) {
|
|
unset($_SERVER['QUERY_STRING']);
|
|
} else {
|
|
$_SERVER['QUERY_STRING'] = $previous;
|
|
}
|
|
}
|
|
}
|
|
|
|
public function testNotesSaveRequiresUser(): void {
|
|
$this->userSession->method('getUser')->willReturn(null);
|
|
|
|
$response = $this->controller->notesSave();
|
|
$this->assertSame(Http::STATUS_UNAUTHORIZED, $response->getStatus());
|
|
}
|
|
|
|
public function testNotesSaveRejectsInvalidJson(): void {
|
|
$user = $this->createMock(IUser::class);
|
|
$user->method('getUID')->willReturn('admin');
|
|
$this->userSession->method('getUser')->willReturn($user);
|
|
|
|
$this->controller = new NotesController(
|
|
'opsdash',
|
|
$this->request,
|
|
$this->userSession,
|
|
$this->createMock(LoggerInterface::class),
|
|
$this->notesService,
|
|
);
|
|
|
|
$data = $this->controller->notesSave();
|
|
$this->assertSame(Http::STATUS_BAD_REQUEST, $data->getStatus());
|
|
$this->assertSame(['message' => 'invalid json'], $data->getData());
|
|
}
|
|
|
|
public function testNotesSaveRejectsMissingRequestToken(): void {
|
|
$user = $this->createMock(IUser::class);
|
|
$user->method('getUID')->willReturn('admin');
|
|
$this->userSession->method('getUser')->willReturn($user);
|
|
|
|
$request = $this->createMock(IRequest::class);
|
|
$request->method('getHeader')->willReturn('');
|
|
$request->method('getParam')->willReturn('');
|
|
|
|
$controller = new NotesController(
|
|
'opsdash',
|
|
$request,
|
|
$this->userSession,
|
|
$this->createMock(LoggerInterface::class),
|
|
$this->notesService,
|
|
);
|
|
|
|
$response = $controller->notesSave();
|
|
$this->assertSame(Http::STATUS_PRECONDITION_FAILED, $response->getStatus());
|
|
$this->assertSame(['message' => 'missing requesttoken'], $response->getData());
|
|
}
|
|
|
|
public function testNotesSaveRejectsInvalidRequestToken(): void {
|
|
$user = $this->createMock(IUser::class);
|
|
$user->method('getUID')->willReturn('admin');
|
|
$this->userSession->method('getUser')->willReturn($user);
|
|
|
|
$request = $this->createMock(IRequest::class);
|
|
$request->method('getHeader')->willReturn('token');
|
|
$request->method('passesCSRFCheck')->willReturn(false);
|
|
|
|
$controller = new NotesController(
|
|
'opsdash',
|
|
$request,
|
|
$this->userSession,
|
|
$this->createMock(LoggerInterface::class),
|
|
$this->notesService,
|
|
);
|
|
|
|
$response = $controller->notesSave();
|
|
$this->assertSame(Http::STATUS_PRECONDITION_FAILED, $response->getStatus());
|
|
$this->assertSame(['message' => 'invalid requesttoken'], $response->getData());
|
|
}
|
|
|
|
public function testNotesSaveReturnsOkOnSuccess(): void {
|
|
$user = $this->createMock(IUser::class);
|
|
$user->method('getUID')->willReturn('admin');
|
|
$this->userSession->method('getUser')->willReturn($user);
|
|
|
|
$request = $this->createMock(IRequest::class);
|
|
$request->method('getHeader')->willReturn('token');
|
|
$request->method('passesCSRFCheck')->willReturn(true);
|
|
|
|
$this->notesService
|
|
->expects($this->once())
|
|
->method('saveNotes')
|
|
->with('admin', 'week', 1, 'hello')
|
|
->willReturn(true);
|
|
|
|
$controller = new NotesController(
|
|
'opsdash',
|
|
$request,
|
|
$this->userSession,
|
|
$this->createMock(LoggerInterface::class),
|
|
$this->notesService,
|
|
);
|
|
|
|
$payload = '{"range":"week","offset":1,"content":"hello"}';
|
|
NotesControllerInputStream::setInput($payload);
|
|
$hadPhpWrapper = in_array('php', stream_get_wrappers(), true);
|
|
if ($hadPhpWrapper) {
|
|
stream_wrapper_unregister('php');
|
|
}
|
|
stream_wrapper_register('php', NotesControllerInputStream::class);
|
|
|
|
try {
|
|
$response = $controller->notesSave();
|
|
} finally {
|
|
if ($hadPhpWrapper) {
|
|
stream_wrapper_restore('php');
|
|
} else {
|
|
stream_wrapper_unregister('php');
|
|
}
|
|
}
|
|
|
|
$this->assertSame(Http::STATUS_OK, $response->getStatus());
|
|
$this->assertSame(['ok' => true], $response->getData());
|
|
}
|
|
|
|
public function testNotesSaveReturnsErrorOnFailure(): void {
|
|
$user = $this->createMock(IUser::class);
|
|
$user->method('getUID')->willReturn('admin');
|
|
$this->userSession->method('getUser')->willReturn($user);
|
|
|
|
$request = $this->createMock(IRequest::class);
|
|
$request->method('getHeader')->willReturn('token');
|
|
$request->method('passesCSRFCheck')->willReturn(true);
|
|
|
|
$this->notesService
|
|
->expects($this->once())
|
|
->method('saveNotes')
|
|
->with('admin', 'week', 0, 'fail')
|
|
->willReturn(false);
|
|
|
|
$controller = new NotesController(
|
|
'opsdash',
|
|
$request,
|
|
$this->userSession,
|
|
$this->createMock(LoggerInterface::class),
|
|
$this->notesService,
|
|
);
|
|
|
|
$payload = '{"range":"week","offset":0,"content":"fail"}';
|
|
NotesControllerInputStream::setInput($payload);
|
|
$hadPhpWrapper = in_array('php', stream_get_wrappers(), true);
|
|
if ($hadPhpWrapper) {
|
|
stream_wrapper_unregister('php');
|
|
}
|
|
stream_wrapper_register('php', NotesControllerInputStream::class);
|
|
|
|
try {
|
|
$response = $controller->notesSave();
|
|
} finally {
|
|
if ($hadPhpWrapper) {
|
|
stream_wrapper_restore('php');
|
|
} else {
|
|
stream_wrapper_unregister('php');
|
|
}
|
|
}
|
|
|
|
$this->assertSame(Http::STATUS_INTERNAL_SERVER_ERROR, $response->getStatus());
|
|
$this->assertSame(['message' => 'error'], $response->getData());
|
|
}
|
|
}
|
|
final class NotesControllerInputStream {
|
|
public $context;
|
|
|
|
private int $index = 0;
|
|
private static string $input = '';
|
|
|
|
public static function setInput(string $input): void {
|
|
self::$input = $input;
|
|
}
|
|
|
|
public function stream_open(string $path, string $mode, int $options, ?string &$openedPath): bool {
|
|
$this->index = 0;
|
|
return true;
|
|
}
|
|
|
|
public function stream_read(int $count): string {
|
|
$chunk = substr(self::$input, $this->index, $count);
|
|
$this->index += strlen($chunk);
|
|
return $chunk;
|
|
}
|
|
|
|
public function stream_eof(): bool {
|
|
return $this->index >= strlen(self::$input);
|
|
}
|
|
|
|
public function stream_stat(): array {
|
|
return [];
|
|
}
|
|
}
|