UserStatusControllerTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2020, Georg Ehrke
  5. *
  6. * @author Georg Ehrke <oc.list@georgehrke.com>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. *
  9. * @license GNU AGPL version 3 or any later version
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU Affero General Public License as
  13. * published by the Free Software Foundation, either version 3 of the
  14. * License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU Affero General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Affero General Public License
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. *
  24. */
  25. namespace OCA\UserStatus\Tests\Controller;
  26. use OCA\DAV\CalDAV\Status\StatusService as CalendarStatusService;
  27. use OCA\UserStatus\Controller\UserStatusController;
  28. use OCA\UserStatus\Db\UserStatus;
  29. use OCA\UserStatus\Exception\InvalidClearAtException;
  30. use OCA\UserStatus\Exception\InvalidMessageIdException;
  31. use OCA\UserStatus\Exception\InvalidStatusIconException;
  32. use OCA\UserStatus\Exception\InvalidStatusTypeException;
  33. use OCA\UserStatus\Exception\StatusMessageTooLongException;
  34. use OCA\UserStatus\Service\StatusService;
  35. use OCP\AppFramework\Db\DoesNotExistException;
  36. use OCP\AppFramework\OCS\OCSBadRequestException;
  37. use OCP\AppFramework\OCS\OCSNotFoundException;
  38. use OCP\IRequest;
  39. use Psr\Log\LoggerInterface;
  40. use Test\TestCase;
  41. use Throwable;
  42. class UserStatusControllerTest extends TestCase {
  43. /** @var LoggerInterface|\PHPUnit\Framework\MockObject\MockObject */
  44. private $logger;
  45. /** @var StatusService|\PHPUnit\Framework\MockObject\MockObject */
  46. private $statusService;
  47. /** @var CalendarStatusService|\PHPUnit\Framework\MockObject\MockObject $calendarStatusService */
  48. private $calendarStatusService;
  49. /** @var UserStatusController */
  50. private $controller;
  51. protected function setUp(): void {
  52. parent::setUp();
  53. $request = $this->createMock(IRequest::class);
  54. $userId = 'john.doe';
  55. $this->logger = $this->createMock(LoggerInterface::class);
  56. $this->statusService = $this->createMock(StatusService::class);
  57. $this->calendarStatusService = $this->createMock(CalendarStatusService::class);
  58. $this->controller = new UserStatusController(
  59. 'user_status',
  60. $request,
  61. $userId,
  62. $this->logger,
  63. $this->statusService,
  64. $this->calendarStatusService,
  65. );
  66. }
  67. public function testGetStatus(): void {
  68. $userStatus = $this->getUserStatus();
  69. $this->statusService->expects($this->once())
  70. ->method('findByUserId')
  71. ->with('john.doe')
  72. ->willReturn($userStatus);
  73. $response = $this->controller->getStatus();
  74. $this->assertEquals([
  75. 'userId' => 'john.doe',
  76. 'status' => 'invisible',
  77. 'icon' => '🏝',
  78. 'message' => 'On vacation',
  79. 'clearAt' => 60000,
  80. 'statusIsUserDefined' => true,
  81. 'messageIsPredefined' => false,
  82. 'messageId' => null,
  83. ], $response->getData());
  84. }
  85. public function testGetStatusDoesNotExist(): void {
  86. $this->calendarStatusService->expects(self::once())
  87. ->method('processCalendarStatus')
  88. ->with('john.doe');
  89. $this->statusService->expects($this->once())
  90. ->method('findByUserId')
  91. ->with('john.doe')
  92. ->willThrowException(new DoesNotExistException(''));
  93. $this->expectException(OCSNotFoundException::class);
  94. $this->expectExceptionMessage('No status for the current user');
  95. $this->controller->getStatus();
  96. }
  97. /**
  98. * @param string $statusType
  99. * @param string|null $statusIcon
  100. * @param string|null $message
  101. * @param int|null $clearAt
  102. * @param bool $expectSuccess
  103. * @param bool $expectException
  104. * @param Throwable|null $exception
  105. * @param bool $expectLogger
  106. * @param string|null $expectedLogMessage
  107. *
  108. * @dataProvider setStatusDataProvider
  109. */
  110. public function testSetStatus(string $statusType,
  111. ?string $statusIcon,
  112. ?string $message,
  113. ?int $clearAt,
  114. bool $expectSuccess,
  115. bool $expectException,
  116. ?Throwable $exception,
  117. bool $expectLogger,
  118. ?string $expectedLogMessage): void {
  119. $userStatus = $this->getUserStatus();
  120. if ($expectException) {
  121. $this->statusService->expects($this->once())
  122. ->method('setStatus')
  123. ->with('john.doe', $statusType, null, true)
  124. ->willThrowException($exception);
  125. } else {
  126. $this->statusService->expects($this->once())
  127. ->method('setStatus')
  128. ->with('john.doe', $statusType, null, true)
  129. ->willReturn($userStatus);
  130. }
  131. if ($expectLogger) {
  132. $this->logger->expects($this->once())
  133. ->method('debug')
  134. ->with($expectedLogMessage);
  135. }
  136. if ($expectException) {
  137. $this->expectException(OCSBadRequestException::class);
  138. $this->expectExceptionMessage('Original exception message');
  139. }
  140. $response = $this->controller->setStatus($statusType);
  141. if ($expectSuccess) {
  142. $this->assertEquals([
  143. 'userId' => 'john.doe',
  144. 'status' => 'invisible',
  145. 'icon' => '🏝',
  146. 'message' => 'On vacation',
  147. 'clearAt' => 60000,
  148. 'statusIsUserDefined' => true,
  149. 'messageIsPredefined' => false,
  150. 'messageId' => null,
  151. ], $response->getData());
  152. }
  153. }
  154. public function setStatusDataProvider(): array {
  155. return [
  156. ['busy', '👨🏽‍💻', 'Busy developing the status feature', 500, true, false, null, false, null],
  157. ['busy', '👨🏽‍💻', 'Busy developing the status feature', 500, false, true, new InvalidStatusTypeException('Original exception message'), true,
  158. 'New user-status for "john.doe" was rejected due to an invalid status type "busy"'],
  159. ];
  160. }
  161. /**
  162. * @param string $messageId
  163. * @param int|null $clearAt
  164. * @param bool $expectSuccess
  165. * @param bool $expectException
  166. * @param Throwable|null $exception
  167. * @param bool $expectLogger
  168. * @param string|null $expectedLogMessage
  169. *
  170. * @dataProvider setPredefinedMessageDataProvider
  171. */
  172. public function testSetPredefinedMessage(string $messageId,
  173. ?int $clearAt,
  174. bool $expectSuccess,
  175. bool $expectException,
  176. ?Throwable $exception,
  177. bool $expectLogger,
  178. ?string $expectedLogMessage): void {
  179. $userStatus = $this->getUserStatus();
  180. if ($expectException) {
  181. $this->statusService->expects($this->once())
  182. ->method('setPredefinedMessage')
  183. ->with('john.doe', $messageId, $clearAt)
  184. ->willThrowException($exception);
  185. } else {
  186. $this->statusService->expects($this->once())
  187. ->method('setPredefinedMessage')
  188. ->with('john.doe', $messageId, $clearAt)
  189. ->willReturn($userStatus);
  190. }
  191. if ($expectLogger) {
  192. $this->logger->expects($this->once())
  193. ->method('debug')
  194. ->with($expectedLogMessage);
  195. }
  196. if ($expectException) {
  197. $this->expectException(OCSBadRequestException::class);
  198. $this->expectExceptionMessage('Original exception message');
  199. }
  200. $response = $this->controller->setPredefinedMessage($messageId, $clearAt);
  201. if ($expectSuccess) {
  202. $this->assertEquals([
  203. 'userId' => 'john.doe',
  204. 'status' => 'invisible',
  205. 'icon' => '🏝',
  206. 'message' => 'On vacation',
  207. 'clearAt' => 60000,
  208. 'statusIsUserDefined' => true,
  209. 'messageIsPredefined' => false,
  210. 'messageId' => null,
  211. ], $response->getData());
  212. }
  213. }
  214. public function setPredefinedMessageDataProvider(): array {
  215. return [
  216. ['messageId-42', 500, true, false, null, false, null],
  217. ['messageId-42', 500, false, true, new InvalidClearAtException('Original exception message'), true,
  218. 'New user-status for "john.doe" was rejected due to an invalid clearAt value "500"'],
  219. ['messageId-42', 500, false, true, new InvalidMessageIdException('Original exception message'), true,
  220. 'New user-status for "john.doe" was rejected due to an invalid message-id "messageId-42"'],
  221. ];
  222. }
  223. /**
  224. * @param string|null $statusIcon
  225. * @param string $message
  226. * @param int|null $clearAt
  227. * @param bool $expectSuccess
  228. * @param bool $expectException
  229. * @param Throwable|null $exception
  230. * @param bool $expectLogger
  231. * @param string|null $expectedLogMessage
  232. * @param bool $expectSuccessAsReset
  233. *
  234. * @dataProvider setCustomMessageDataProvider
  235. */
  236. public function testSetCustomMessage(?string $statusIcon,
  237. string $message,
  238. ?int $clearAt,
  239. bool $expectSuccess,
  240. bool $expectException,
  241. ?Throwable $exception,
  242. bool $expectLogger,
  243. ?string $expectedLogMessage,
  244. bool $expectSuccessAsReset = false): void {
  245. $userStatus = $this->getUserStatus();
  246. if ($expectException) {
  247. $this->statusService->expects($this->once())
  248. ->method('setCustomMessage')
  249. ->with('john.doe', $statusIcon, $message, $clearAt)
  250. ->willThrowException($exception);
  251. } else {
  252. if ($expectSuccessAsReset) {
  253. $this->statusService->expects($this->never())
  254. ->method('setCustomMessage');
  255. $this->statusService->expects($this->once())
  256. ->method('clearMessage')
  257. ->with('john.doe');
  258. $this->statusService->expects($this->once())
  259. ->method('findByUserId')
  260. ->with('john.doe')
  261. ->willReturn($userStatus);
  262. } else {
  263. $this->statusService->expects($this->once())
  264. ->method('setCustomMessage')
  265. ->with('john.doe', $statusIcon, $message, $clearAt)
  266. ->willReturn($userStatus);
  267. $this->statusService->expects($this->never())
  268. ->method('clearMessage');
  269. }
  270. }
  271. if ($expectLogger) {
  272. $this->logger->expects($this->once())
  273. ->method('debug')
  274. ->with($expectedLogMessage);
  275. }
  276. if ($expectException) {
  277. $this->expectException(OCSBadRequestException::class);
  278. $this->expectExceptionMessage('Original exception message');
  279. }
  280. $response = $this->controller->setCustomMessage($statusIcon, $message, $clearAt);
  281. if ($expectSuccess) {
  282. $this->assertEquals([
  283. 'userId' => 'john.doe',
  284. 'status' => 'invisible',
  285. 'icon' => '🏝',
  286. 'message' => 'On vacation',
  287. 'clearAt' => 60000,
  288. 'statusIsUserDefined' => true,
  289. 'messageIsPredefined' => false,
  290. 'messageId' => null,
  291. ], $response->getData());
  292. }
  293. }
  294. public function setCustomMessageDataProvider(): array {
  295. return [
  296. ['👨🏽‍💻', 'Busy developing the status feature', 500, true, false, null, false, null],
  297. ['👨🏽‍💻', '', 500, true, false, null, false, null, false],
  298. ['👨🏽‍💻', '', 0, true, false, null, false, null, false],
  299. ['👨🏽‍💻', 'Busy developing the status feature', 500, false, true, new InvalidClearAtException('Original exception message'), true,
  300. 'New user-status for "john.doe" was rejected due to an invalid clearAt value "500"'],
  301. ['👨🏽‍💻', 'Busy developing the status feature', 500, false, true, new InvalidStatusIconException('Original exception message'), true,
  302. 'New user-status for "john.doe" was rejected due to an invalid icon value "👨🏽‍💻"'],
  303. ['👨🏽‍💻', 'Busy developing the status feature', 500, false, true, new StatusMessageTooLongException('Original exception message'), true,
  304. 'New user-status for "john.doe" was rejected due to a too long status message.'],
  305. ];
  306. }
  307. public function testClearMessage(): void {
  308. $this->statusService->expects($this->once())
  309. ->method('clearMessage')
  310. ->with('john.doe');
  311. $response = $this->controller->clearMessage();
  312. $this->assertEquals([], $response->getData());
  313. }
  314. private function getUserStatus(): UserStatus {
  315. $userStatus = new UserStatus();
  316. $userStatus->setId(1337);
  317. $userStatus->setUserId('john.doe');
  318. $userStatus->setStatus('invisible');
  319. $userStatus->setStatusTimestamp(5000);
  320. $userStatus->setIsUserDefined(true);
  321. $userStatus->setCustomIcon('🏝');
  322. $userStatus->setCustomMessage('On vacation');
  323. $userStatus->setClearAt(60000);
  324. return $userStatus;
  325. }
  326. }