mirror of
https://github.com/nextcloud/server.git
synced 2025-02-11 11:39:27 +00:00
876 lines
30 KiB
PHP
876 lines
30 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
namespace OCA\UserStatus\Tests\Service;
|
|
|
|
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
|
use OC\DB\Exceptions\DbalException;
|
|
use OCA\UserStatus\Db\UserStatus;
|
|
use OCA\UserStatus\Db\UserStatusMapper;
|
|
use OCA\UserStatus\Exception\InvalidClearAtException;
|
|
use OCA\UserStatus\Exception\InvalidMessageIdException;
|
|
use OCA\UserStatus\Exception\InvalidStatusIconException;
|
|
use OCA\UserStatus\Exception\InvalidStatusTypeException;
|
|
use OCA\UserStatus\Exception\StatusMessageTooLongException;
|
|
use OCA\UserStatus\Service\PredefinedStatusService;
|
|
use OCA\UserStatus\Service\StatusService;
|
|
use OCP\AppFramework\Db\DoesNotExistException;
|
|
use OCP\AppFramework\Utility\ITimeFactory;
|
|
use OCP\DB\Exception;
|
|
use OCP\IConfig;
|
|
use OCP\IEmojiHelper;
|
|
use OCP\IUserManager;
|
|
use OCP\UserStatus\IUserStatus;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use Psr\Log\LoggerInterface;
|
|
use Test\TestCase;
|
|
|
|
class StatusServiceTest extends TestCase {
|
|
|
|
/** @var UserStatusMapper|MockObject */
|
|
private $mapper;
|
|
|
|
/** @var ITimeFactory|MockObject */
|
|
private $timeFactory;
|
|
|
|
/** @var PredefinedStatusService|MockObject */
|
|
private $predefinedStatusService;
|
|
|
|
/** @var IEmojiHelper|MockObject */
|
|
private $emojiHelper;
|
|
|
|
/** @var IConfig|MockObject */
|
|
private $config;
|
|
|
|
/** @var IUserManager|MockObject */
|
|
private $userManager;
|
|
|
|
/** @var LoggerInterface|MockObject */
|
|
private $logger;
|
|
|
|
private StatusService $service;
|
|
|
|
protected function setUp(): void {
|
|
parent::setUp();
|
|
|
|
$this->mapper = $this->createMock(UserStatusMapper::class);
|
|
$this->timeFactory = $this->createMock(ITimeFactory::class);
|
|
$this->predefinedStatusService = $this->createMock(PredefinedStatusService::class);
|
|
$this->emojiHelper = $this->createMock(IEmojiHelper::class);
|
|
$this->userManager = $this->createMock(IUserManager::class);
|
|
$this->config = $this->createMock(IConfig::class);
|
|
$this->logger = $this->createMock(LoggerInterface::class);
|
|
|
|
$this->config->method('getAppValue')
|
|
->willReturnMap([
|
|
['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
|
|
['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'no']
|
|
]);
|
|
|
|
$this->service = new StatusService($this->mapper,
|
|
$this->timeFactory,
|
|
$this->predefinedStatusService,
|
|
$this->emojiHelper,
|
|
$this->config,
|
|
$this->userManager,
|
|
$this->logger,
|
|
);
|
|
}
|
|
|
|
public function testFindAll(): void {
|
|
$status1 = $this->createMock(UserStatus::class);
|
|
$status2 = $this->createMock(UserStatus::class);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('findAll')
|
|
->with(20, 50)
|
|
->willReturn([$status1, $status2]);
|
|
|
|
$this->assertEquals([
|
|
$status1,
|
|
$status2,
|
|
], $this->service->findAll(20, 50));
|
|
}
|
|
|
|
public function testFindAllRecentStatusChanges(): void {
|
|
$status1 = $this->createMock(UserStatus::class);
|
|
$status2 = $this->createMock(UserStatus::class);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('findAllRecent')
|
|
->with(20, 50)
|
|
->willReturn([$status1, $status2]);
|
|
|
|
$this->assertEquals([
|
|
$status1,
|
|
$status2,
|
|
], $this->service->findAllRecentStatusChanges(20, 50));
|
|
}
|
|
|
|
public function testFindAllRecentStatusChangesNoEnumeration(): void {
|
|
$status1 = $this->createMock(UserStatus::class);
|
|
$status2 = $this->createMock(UserStatus::class);
|
|
|
|
$this->mapper->method('findAllRecent')
|
|
->with(20, 50)
|
|
->willReturn([$status1, $status2]);
|
|
|
|
// Rebuild $this->service with user enumeration turned off
|
|
$this->config = $this->createMock(IConfig::class);
|
|
|
|
$this->config->method('getAppValue')
|
|
->willReturnMap([
|
|
['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'no'],
|
|
['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'no']
|
|
]);
|
|
|
|
$this->service = new StatusService($this->mapper,
|
|
$this->timeFactory,
|
|
$this->predefinedStatusService,
|
|
$this->emojiHelper,
|
|
$this->config,
|
|
$this->userManager,
|
|
$this->logger,
|
|
);
|
|
|
|
$this->assertEquals([], $this->service->findAllRecentStatusChanges(20, 50));
|
|
|
|
// Rebuild $this->service with user enumeration limited to common groups
|
|
$this->config = $this->createMock(IConfig::class);
|
|
|
|
$this->config->method('getAppValue')
|
|
->willReturnMap([
|
|
['core', 'shareapi_allow_share_dialog_user_enumeration', 'yes', 'yes'],
|
|
['core', 'shareapi_restrict_user_enumeration_to_group', 'no', 'yes']
|
|
]);
|
|
|
|
$this->service = new StatusService($this->mapper,
|
|
$this->timeFactory,
|
|
$this->predefinedStatusService,
|
|
$this->emojiHelper,
|
|
$this->config,
|
|
$this->userManager,
|
|
$this->logger,
|
|
);
|
|
|
|
$this->assertEquals([], $this->service->findAllRecentStatusChanges(20, 50));
|
|
}
|
|
|
|
public function testFindByUserIdDoesNotExist(): void {
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john.doe')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$this->expectException(DoesNotExistException::class);
|
|
$this->service->findByUserId('john.doe');
|
|
}
|
|
|
|
public function testFindAllAddDefaultMessage(): void {
|
|
$status = new UserStatus();
|
|
$status->setMessageId('commuting');
|
|
|
|
$this->predefinedStatusService->expects($this->once())
|
|
->method('getDefaultStatusById')
|
|
->with('commuting')
|
|
->willReturn([
|
|
'id' => 'commuting',
|
|
'icon' => '🚌',
|
|
'message' => 'Commuting',
|
|
'clearAt' => [
|
|
'type' => 'period',
|
|
'time' => 1800,
|
|
],
|
|
]);
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john.doe')
|
|
->willReturn($status);
|
|
|
|
$this->assertEquals($status, $this->service->findByUserId('john.doe'));
|
|
$this->assertEquals('🚌', $status->getCustomIcon());
|
|
$this->assertEquals('Commuting', $status->getCustomMessage());
|
|
}
|
|
|
|
public function testFindAllClearStatus(): void {
|
|
$status = new UserStatus();
|
|
$status->setStatus('online');
|
|
$status->setStatusTimestamp(1000);
|
|
$status->setIsUserDefined(true);
|
|
|
|
$this->timeFactory->method('getTime')
|
|
->willReturn(2600);
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john.doe')
|
|
->willReturn($status);
|
|
|
|
$this->assertEquals($status, $this->service->findByUserId('john.doe'));
|
|
$this->assertEquals('offline', $status->getStatus());
|
|
$this->assertEquals(2600, $status->getStatusTimestamp());
|
|
$this->assertFalse($status->getIsUserDefined());
|
|
}
|
|
|
|
public function testFindAllClearMessage(): void {
|
|
$status = new UserStatus();
|
|
$status->setClearAt(50);
|
|
$status->setMessageId('commuting');
|
|
$status->setStatusTimestamp(60);
|
|
|
|
$this->timeFactory->method('getTime')
|
|
->willReturn(60);
|
|
$this->predefinedStatusService->expects($this->never())
|
|
->method('getDefaultStatusById');
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john.doe')
|
|
->willReturn($status);
|
|
$this->assertEquals($status, $this->service->findByUserId('john.doe'));
|
|
$this->assertNull($status->getClearAt());
|
|
$this->assertNull($status->getMessageId());
|
|
}
|
|
|
|
/**
|
|
* @param string $userId
|
|
* @param string $status
|
|
* @param int|null $statusTimestamp
|
|
* @param bool $isUserDefined
|
|
* @param bool $expectExisting
|
|
* @param bool $expectSuccess
|
|
* @param bool $expectTimeFactory
|
|
* @param bool $expectException
|
|
* @param string|null $expectedExceptionClass
|
|
* @param string|null $expectedExceptionMessage
|
|
*
|
|
* @dataProvider setStatusDataProvider
|
|
*/
|
|
public function testSetStatus(string $userId,
|
|
string $status,
|
|
?int $statusTimestamp,
|
|
bool $isUserDefined,
|
|
bool $expectExisting,
|
|
bool $expectSuccess,
|
|
bool $expectTimeFactory,
|
|
bool $expectException,
|
|
?string $expectedExceptionClass,
|
|
?string $expectedExceptionMessage): void {
|
|
$userStatus = new UserStatus();
|
|
|
|
if ($expectExisting) {
|
|
$userStatus->setId(42);
|
|
$userStatus->setUserId($userId);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with($userId)
|
|
->willReturn($userStatus);
|
|
} else {
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with($userId)
|
|
->willThrowException(new DoesNotExistException(''));
|
|
}
|
|
|
|
if ($expectTimeFactory) {
|
|
$this->timeFactory
|
|
->method('getTime')
|
|
->willReturn(40);
|
|
}
|
|
|
|
if ($expectException) {
|
|
$this->expectException($expectedExceptionClass);
|
|
$this->expectExceptionMessage($expectedExceptionMessage);
|
|
|
|
$this->service->setStatus($userId, $status, $statusTimestamp, $isUserDefined);
|
|
}
|
|
|
|
if ($expectSuccess) {
|
|
if ($expectExisting) {
|
|
$this->mapper->expects($this->once())
|
|
->method('update')
|
|
->willReturnArgument(0);
|
|
} else {
|
|
$this->mapper->expects($this->once())
|
|
->method('insert')
|
|
->willReturnArgument(0);
|
|
}
|
|
|
|
$actual = $this->service->setStatus($userId, $status, $statusTimestamp, $isUserDefined);
|
|
|
|
$this->assertEquals('john.doe', $actual->getUserId());
|
|
$this->assertEquals($status, $actual->getStatus());
|
|
$this->assertEquals($statusTimestamp ?? 40, $actual->getStatusTimestamp());
|
|
$this->assertEquals($isUserDefined, $actual->getIsUserDefined());
|
|
}
|
|
}
|
|
|
|
public function setStatusDataProvider(): array {
|
|
return [
|
|
['john.doe', 'online', 50, true, true, true, false, false, null, null],
|
|
['john.doe', 'online', 50, true, false, true, false, false, null, null],
|
|
['john.doe', 'online', 50, false, true, true, false, false, null, null],
|
|
['john.doe', 'online', 50, false, false, true, false, false, null, null],
|
|
['john.doe', 'online', null, true, true, true, true, false, null, null],
|
|
['john.doe', 'online', null, true, false, true, true, false, null, null],
|
|
['john.doe', 'online', null, false, true, true, true, false, null, null],
|
|
['john.doe', 'online', null, false, false, true, true, false, null, null],
|
|
|
|
['john.doe', 'away', 50, true, true, true, false, false, null, null],
|
|
['john.doe', 'away', 50, true, false, true, false, false, null, null],
|
|
['john.doe', 'away', 50, false, true, true, false, false, null, null],
|
|
['john.doe', 'away', 50, false, false, true, false, false, null, null],
|
|
['john.doe', 'away', null, true, true, true, true, false, null, null],
|
|
['john.doe', 'away', null, true, false, true, true, false, null, null],
|
|
['john.doe', 'away', null, false, true, true, true, false, null, null],
|
|
['john.doe', 'away', null, false, false, true, true, false, null, null],
|
|
|
|
['john.doe', 'dnd', 50, true, true, true, false, false, null, null],
|
|
['john.doe', 'dnd', 50, true, false, true, false, false, null, null],
|
|
['john.doe', 'dnd', 50, false, true, true, false, false, null, null],
|
|
['john.doe', 'dnd', 50, false, false, true, false, false, null, null],
|
|
['john.doe', 'dnd', null, true, true, true, true, false, null, null],
|
|
['john.doe', 'dnd', null, true, false, true, true, false, null, null],
|
|
['john.doe', 'dnd', null, false, true, true, true, false, null, null],
|
|
['john.doe', 'dnd', null, false, false, true, true, false, null, null],
|
|
|
|
['john.doe', 'invisible', 50, true, true, true, false, false, null, null],
|
|
['john.doe', 'invisible', 50, true, false, true, false, false, null, null],
|
|
['john.doe', 'invisible', 50, false, true, true, false, false, null, null],
|
|
['john.doe', 'invisible', 50, false, false, true, false, false, null, null],
|
|
['john.doe', 'invisible', null, true, true, true, true, false, null, null],
|
|
['john.doe', 'invisible', null, true, false, true, true, false, null, null],
|
|
['john.doe', 'invisible', null, false, true, true, true, false, null, null],
|
|
['john.doe', 'invisible', null, false, false, true, true, false, null, null],
|
|
|
|
['john.doe', 'offline', 50, true, true, true, false, false, null, null],
|
|
['john.doe', 'offline', 50, true, false, true, false, false, null, null],
|
|
['john.doe', 'offline', 50, false, true, true, false, false, null, null],
|
|
['john.doe', 'offline', 50, false, false, true, false, false, null, null],
|
|
['john.doe', 'offline', null, true, true, true, true, false, null, null],
|
|
['john.doe', 'offline', null, true, false, true, true, false, null, null],
|
|
['john.doe', 'offline', null, false, true, true, true, false, null, null],
|
|
['john.doe', 'offline', null, false, false, true, true, false, null, null],
|
|
|
|
['john.doe', 'illegal-status', 50, true, true, false, false, true, InvalidStatusTypeException::class, 'Status-type "illegal-status" is not supported'],
|
|
['john.doe', 'illegal-status', 50, true, false, false, false, true, InvalidStatusTypeException::class, 'Status-type "illegal-status" is not supported'],
|
|
['john.doe', 'illegal-status', 50, false, true, false, false, true, InvalidStatusTypeException::class, 'Status-type "illegal-status" is not supported'],
|
|
['john.doe', 'illegal-status', 50, false, false, false, false, true, InvalidStatusTypeException::class, 'Status-type "illegal-status" is not supported'],
|
|
['john.doe', 'illegal-status', null, true, true, false, true, true, InvalidStatusTypeException::class, 'Status-type "illegal-status" is not supported'],
|
|
['john.doe', 'illegal-status', null, true, false, false, true, true, InvalidStatusTypeException::class, 'Status-type "illegal-status" is not supported'],
|
|
['john.doe', 'illegal-status', null, false, true, false, true, true, InvalidStatusTypeException::class, 'Status-type "illegal-status" is not supported'],
|
|
['john.doe', 'illegal-status', null, false, false, false, true, true, InvalidStatusTypeException::class, 'Status-type "illegal-status" is not supported'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param string $userId
|
|
* @param string $messageId
|
|
* @param bool $isValidMessageId
|
|
* @param int|null $clearAt
|
|
* @param bool $expectExisting
|
|
* @param bool $expectSuccess
|
|
* @param bool $expectException
|
|
* @param string|null $expectedExceptionClass
|
|
* @param string|null $expectedExceptionMessage
|
|
*
|
|
* @dataProvider setPredefinedMessageDataProvider
|
|
*/
|
|
public function testSetPredefinedMessage(string $userId,
|
|
string $messageId,
|
|
bool $isValidMessageId,
|
|
?int $clearAt,
|
|
bool $expectExisting,
|
|
bool $expectSuccess,
|
|
bool $expectException,
|
|
?string $expectedExceptionClass,
|
|
?string $expectedExceptionMessage): void {
|
|
$userStatus = new UserStatus();
|
|
|
|
if ($expectExisting) {
|
|
$userStatus->setId(42);
|
|
$userStatus->setUserId($userId);
|
|
$userStatus->setStatus('offline');
|
|
$userStatus->setStatusTimestamp(0);
|
|
$userStatus->setIsUserDefined(false);
|
|
$userStatus->setCustomIcon('😀');
|
|
$userStatus->setCustomMessage('Foo');
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with($userId)
|
|
->willReturn($userStatus);
|
|
} else {
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with($userId)
|
|
->willThrowException(new DoesNotExistException(''));
|
|
}
|
|
|
|
$this->predefinedStatusService->expects($this->once())
|
|
->method('isValidId')
|
|
->with($messageId)
|
|
->willReturn($isValidMessageId);
|
|
|
|
$this->timeFactory
|
|
->method('getTime')
|
|
->willReturn(40);
|
|
|
|
if ($expectException) {
|
|
$this->expectException($expectedExceptionClass);
|
|
$this->expectExceptionMessage($expectedExceptionMessage);
|
|
|
|
$this->service->setPredefinedMessage($userId, $messageId, $clearAt);
|
|
}
|
|
|
|
if ($expectSuccess) {
|
|
if ($expectExisting) {
|
|
$this->mapper->expects($this->once())
|
|
->method('update')
|
|
->willReturnArgument(0);
|
|
} else {
|
|
$this->mapper->expects($this->once())
|
|
->method('insert')
|
|
->willReturnArgument(0);
|
|
}
|
|
|
|
$actual = $this->service->setPredefinedMessage($userId, $messageId, $clearAt);
|
|
|
|
$this->assertEquals('john.doe', $actual->getUserId());
|
|
$this->assertEquals('offline', $actual->getStatus());
|
|
$this->assertEquals(0, $actual->getStatusTimestamp());
|
|
$this->assertEquals(false, $actual->getIsUserDefined());
|
|
$this->assertEquals($messageId, $actual->getMessageId());
|
|
$this->assertNull($actual->getCustomIcon());
|
|
$this->assertNull($actual->getCustomMessage());
|
|
$this->assertEquals($clearAt, $actual->getClearAt());
|
|
}
|
|
}
|
|
|
|
public function setPredefinedMessageDataProvider(): array {
|
|
return [
|
|
['john.doe', 'sick-leave', true, null, true, true, false, null, null],
|
|
['john.doe', 'sick-leave', true, null, false, true, false, null, null],
|
|
['john.doe', 'sick-leave', true, 20, true, false, true, InvalidClearAtException::class, 'ClearAt is in the past'],
|
|
['john.doe', 'sick-leave', true, 20, false, false, true, InvalidClearAtException::class, 'ClearAt is in the past'],
|
|
['john.doe', 'sick-leave', true, 60, true, true, false, null, null],
|
|
['john.doe', 'sick-leave', true, 60, false, true, false, null, null],
|
|
['john.doe', 'illegal-message-id', false, null, true, false, true, InvalidMessageIdException::class, 'Message-Id "illegal-message-id" is not supported'],
|
|
['john.doe', 'illegal-message-id', false, null, false, false, true, InvalidMessageIdException::class, 'Message-Id "illegal-message-id" is not supported'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param string $userId
|
|
* @param string|null $statusIcon
|
|
* @param bool $supportsEmoji
|
|
* @param string $message
|
|
* @param int|null $clearAt
|
|
* @param bool $expectExisting
|
|
* @param bool $expectSuccess
|
|
* @param bool $expectException
|
|
* @param string|null $expectedExceptionClass
|
|
* @param string|null $expectedExceptionMessage
|
|
*
|
|
* @dataProvider setCustomMessageDataProvider
|
|
*/
|
|
public function testSetCustomMessage(string $userId,
|
|
?string $statusIcon,
|
|
bool $supportsEmoji,
|
|
string $message,
|
|
?int $clearAt,
|
|
bool $expectExisting,
|
|
bool $expectSuccess,
|
|
bool $expectException,
|
|
?string $expectedExceptionClass,
|
|
?string $expectedExceptionMessage): void {
|
|
$userStatus = new UserStatus();
|
|
|
|
if ($expectExisting) {
|
|
$userStatus->setId(42);
|
|
$userStatus->setUserId($userId);
|
|
$userStatus->setStatus('offline');
|
|
$userStatus->setStatusTimestamp(0);
|
|
$userStatus->setIsUserDefined(false);
|
|
$userStatus->setMessageId('messageId-42');
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with($userId)
|
|
->willReturn($userStatus);
|
|
} else {
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with($userId)
|
|
->willThrowException(new DoesNotExistException(''));
|
|
}
|
|
|
|
$this->emojiHelper->method('isValidSingleEmoji')
|
|
->with($statusIcon)
|
|
->willReturn($supportsEmoji);
|
|
|
|
$this->timeFactory
|
|
->method('getTime')
|
|
->willReturn(40);
|
|
|
|
if ($expectException) {
|
|
$this->expectException($expectedExceptionClass);
|
|
$this->expectExceptionMessage($expectedExceptionMessage);
|
|
|
|
$this->service->setCustomMessage($userId, $statusIcon, $message, $clearAt);
|
|
}
|
|
|
|
if ($expectSuccess) {
|
|
if ($expectExisting) {
|
|
$this->mapper->expects($this->once())
|
|
->method('update')
|
|
->willReturnArgument(0);
|
|
} else {
|
|
$this->mapper->expects($this->once())
|
|
->method('insert')
|
|
->willReturnArgument(0);
|
|
}
|
|
|
|
$actual = $this->service->setCustomMessage($userId, $statusIcon, $message, $clearAt);
|
|
|
|
$this->assertEquals('john.doe', $actual->getUserId());
|
|
$this->assertEquals('offline', $actual->getStatus());
|
|
$this->assertEquals(0, $actual->getStatusTimestamp());
|
|
$this->assertEquals(false, $actual->getIsUserDefined());
|
|
$this->assertNull($actual->getMessageId());
|
|
$this->assertEquals($statusIcon, $actual->getCustomIcon());
|
|
$this->assertEquals($message, $actual->getCustomMessage());
|
|
$this->assertEquals($clearAt, $actual->getClearAt());
|
|
}
|
|
}
|
|
|
|
public function setCustomMessageDataProvider(): array {
|
|
return [
|
|
['john.doe', '😁', true, 'Custom message', null, true, true, false, null, null],
|
|
['john.doe', '😁', true, 'Custom message', null, false, true, false, null, null],
|
|
['john.doe', null, false, 'Custom message', null, true, true, false, null, null],
|
|
['john.doe', null, false, 'Custom message', null, false, true, false, null, null],
|
|
['john.doe', '😁', false, 'Custom message', null, true, false, true, InvalidStatusIconException::class, 'Status-Icon is longer than one character'],
|
|
['john.doe', '😁', false, 'Custom message', null, false, false, true, InvalidStatusIconException::class, 'Status-Icon is longer than one character'],
|
|
['john.doe', null, false, 'Custom message that is way too long and violates the maximum length and hence should be rejected', null, true, false, true, StatusMessageTooLongException::class, 'Message is longer than supported length of 80 characters'],
|
|
['john.doe', null, false, 'Custom message that is way too long and violates the maximum length and hence should be rejected', null, false, false, true, StatusMessageTooLongException::class, 'Message is longer than supported length of 80 characters'],
|
|
['john.doe', '😁', true, 'Custom message', 80, true, true, false, null, null],
|
|
['john.doe', '😁', true, 'Custom message', 80, false, true, false, null, null],
|
|
['john.doe', '😁', true, 'Custom message', 20, true, false, true, InvalidClearAtException::class, 'ClearAt is in the past'],
|
|
['john.doe', '😁', true, 'Custom message', 20, false, false, true, InvalidClearAtException::class, 'ClearAt is in the past'],
|
|
];
|
|
}
|
|
|
|
public function testClearStatus(): void {
|
|
$status = new UserStatus();
|
|
$status->setId(1);
|
|
$status->setUserId('john.doe');
|
|
$status->setStatus('dnd');
|
|
$status->setStatusTimestamp(1337);
|
|
$status->setIsUserDefined(true);
|
|
$status->setMessageId('messageId-42');
|
|
$status->setCustomIcon('🙊');
|
|
$status->setCustomMessage('My custom status message');
|
|
$status->setClearAt(42);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john.doe')
|
|
->willReturn($status);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('update')
|
|
->with($status);
|
|
|
|
$actual = $this->service->clearStatus('john.doe');
|
|
$this->assertTrue($actual);
|
|
$this->assertEquals('offline', $status->getStatus());
|
|
$this->assertEquals(0, $status->getStatusTimestamp());
|
|
$this->assertFalse($status->getIsUserDefined());
|
|
}
|
|
|
|
public function testClearStatusDoesNotExist(): void {
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john.doe')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$this->mapper->expects($this->never())
|
|
->method('update');
|
|
|
|
$actual = $this->service->clearStatus('john.doe');
|
|
$this->assertFalse($actual);
|
|
}
|
|
|
|
public function testClearMessage(): void {
|
|
$status = new UserStatus();
|
|
$status->setId(1);
|
|
$status->setUserId('john.doe');
|
|
$status->setStatus('dnd');
|
|
$status->setStatusTimestamp(1337);
|
|
$status->setIsUserDefined(true);
|
|
$status->setMessageId('messageId-42');
|
|
$status->setCustomIcon('🙊');
|
|
$status->setCustomMessage('My custom status message');
|
|
$status->setClearAt(42);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john.doe')
|
|
->willReturn($status);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('update')
|
|
->with($status);
|
|
|
|
$actual = $this->service->clearMessage('john.doe');
|
|
$this->assertTrue($actual);
|
|
$this->assertNull($status->getMessageId());
|
|
$this->assertNull($status->getCustomMessage());
|
|
$this->assertNull($status->getCustomIcon());
|
|
$this->assertNull($status->getClearAt());
|
|
}
|
|
|
|
public function testClearMessageDoesNotExist(): void {
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john.doe')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$this->mapper->expects($this->never())
|
|
->method('update');
|
|
|
|
$actual = $this->service->clearMessage('john.doe');
|
|
$this->assertFalse($actual);
|
|
}
|
|
|
|
public function testRemoveUserStatus(): void {
|
|
$status = $this->createMock(UserStatus::class);
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john.doe')
|
|
->willReturn($status);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('delete')
|
|
->with($status);
|
|
|
|
$actual = $this->service->removeUserStatus('john.doe');
|
|
$this->assertTrue($actual);
|
|
}
|
|
|
|
public function testRemoveUserStatusDoesNotExist(): void {
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john.doe')
|
|
->willThrowException(new DoesNotExistException(''));
|
|
|
|
$this->mapper->expects($this->never())
|
|
->method('delete');
|
|
|
|
$actual = $this->service->removeUserStatus('john.doe');
|
|
$this->assertFalse($actual);
|
|
}
|
|
|
|
public function testCleanStatusAutomaticOnline(): void {
|
|
$status = new UserStatus();
|
|
$status->setStatus(IUserStatus::ONLINE);
|
|
$status->setStatusTimestamp(1337);
|
|
$status->setIsUserDefined(false);
|
|
|
|
$this->mapper->expects(self::once())
|
|
->method('update')
|
|
->with($status);
|
|
|
|
parent::invokePrivate($this->service, 'cleanStatus', [$status]);
|
|
}
|
|
|
|
public function testCleanStatusCustomOffline(): void {
|
|
$status = new UserStatus();
|
|
$status->setStatus(IUserStatus::OFFLINE);
|
|
$status->setStatusTimestamp(1337);
|
|
$status->setIsUserDefined(true);
|
|
|
|
$this->mapper->expects(self::once())
|
|
->method('update')
|
|
->with($status);
|
|
|
|
parent::invokePrivate($this->service, 'cleanStatus', [$status]);
|
|
}
|
|
|
|
public function testCleanStatusCleanedAlready(): void {
|
|
$status = new UserStatus();
|
|
$status->setStatus(IUserStatus::OFFLINE);
|
|
$status->setStatusTimestamp(1337);
|
|
$status->setIsUserDefined(false);
|
|
|
|
// Don't update the status again and again when no value changed
|
|
$this->mapper->expects(self::never())
|
|
->method('update')
|
|
->with($status);
|
|
|
|
parent::invokePrivate($this->service, 'cleanStatus', [$status]);
|
|
}
|
|
|
|
public function testBackupWorkingHasBackupAlready(): void {
|
|
$p = $this->createMock(UniqueConstraintViolationException::class);
|
|
$e = DbalException::wrap($p);
|
|
$this->mapper->expects($this->once())
|
|
->method('createBackupStatus')
|
|
->with('john')
|
|
->willThrowException($e);
|
|
|
|
$this->assertFalse($this->service->backupCurrentStatus('john'));
|
|
}
|
|
|
|
public function testBackupThrowsOther(): void {
|
|
$e = new Exception('', Exception::REASON_CONNECTION_LOST);
|
|
$this->mapper->expects($this->once())
|
|
->method('createBackupStatus')
|
|
->with('john')
|
|
->willThrowException($e);
|
|
|
|
$this->expectException(Exception::class);
|
|
$this->service->backupCurrentStatus('john');
|
|
}
|
|
|
|
public function testBackup(): void {
|
|
$this->mapper->expects($this->once())
|
|
->method('createBackupStatus')
|
|
->with('john')
|
|
->willReturn(true);
|
|
|
|
$this->assertTrue($this->service->backupCurrentStatus('john'));
|
|
}
|
|
|
|
public function testRevertMultipleUserStatus(): void {
|
|
$john = new UserStatus();
|
|
$john->setId(1);
|
|
$john->setStatus(IUserStatus::AWAY);
|
|
$john->setStatusTimestamp(1337);
|
|
$john->setIsUserDefined(false);
|
|
$john->setMessageId('call');
|
|
$john->setUserId('john');
|
|
$john->setIsBackup(false);
|
|
|
|
$johnBackup = new UserStatus();
|
|
$johnBackup->setId(2);
|
|
$johnBackup->setStatus(IUserStatus::ONLINE);
|
|
$johnBackup->setStatusTimestamp(1337);
|
|
$johnBackup->setIsUserDefined(true);
|
|
$johnBackup->setMessageId('hello');
|
|
$johnBackup->setUserId('_john');
|
|
$johnBackup->setIsBackup(true);
|
|
|
|
$noBackup = new UserStatus();
|
|
$noBackup->setId(3);
|
|
$noBackup->setStatus(IUserStatus::AWAY);
|
|
$noBackup->setStatusTimestamp(1337);
|
|
$noBackup->setIsUserDefined(false);
|
|
$noBackup->setMessageId('call');
|
|
$noBackup->setUserId('nobackup');
|
|
$noBackup->setIsBackup(false);
|
|
|
|
$backupOnly = new UserStatus();
|
|
$backupOnly->setId(4);
|
|
$backupOnly->setStatus(IUserStatus::ONLINE);
|
|
$backupOnly->setStatusTimestamp(1337);
|
|
$backupOnly->setIsUserDefined(true);
|
|
$backupOnly->setMessageId('hello');
|
|
$backupOnly->setUserId('_backuponly');
|
|
$backupOnly->setIsBackup(true);
|
|
|
|
$noBackupDND = new UserStatus();
|
|
$noBackupDND->setId(5);
|
|
$noBackupDND->setStatus(IUserStatus::DND);
|
|
$noBackupDND->setStatusTimestamp(1337);
|
|
$noBackupDND->setIsUserDefined(false);
|
|
$noBackupDND->setMessageId('call');
|
|
$noBackupDND->setUserId('nobackupanddnd');
|
|
$noBackupDND->setIsBackup(false);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserIds')
|
|
->with(['john', 'nobackup', 'backuponly', 'nobackupanddnd', '_john', '_nobackup', '_backuponly', '_nobackupanddnd'])
|
|
->willReturn([
|
|
$john,
|
|
$johnBackup,
|
|
$noBackup,
|
|
$backupOnly,
|
|
$noBackupDND,
|
|
]);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('deleteByIds')
|
|
->with([1, 3, 5]);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('restoreBackupStatuses')
|
|
->with([2]);
|
|
|
|
$this->service->revertMultipleUserStatus(['john', 'nobackup', 'backuponly', 'nobackupanddnd'], 'call');
|
|
}
|
|
|
|
public function dataSetUserStatus(): array {
|
|
return [
|
|
[IUserStatus::MESSAGE_CALENDAR_BUSY, '', false],
|
|
|
|
// Call > Meeting
|
|
[IUserStatus::MESSAGE_CALENDAR_BUSY, IUserStatus::MESSAGE_CALL, false],
|
|
[IUserStatus::MESSAGE_CALL, IUserStatus::MESSAGE_CALENDAR_BUSY, true],
|
|
|
|
// Availability > Call&Meeting
|
|
[IUserStatus::MESSAGE_CALENDAR_BUSY, IUserStatus::MESSAGE_AVAILABILITY, false],
|
|
[IUserStatus::MESSAGE_CALL, IUserStatus::MESSAGE_AVAILABILITY, false],
|
|
[IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::MESSAGE_CALENDAR_BUSY, true],
|
|
[IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::MESSAGE_CALL, true],
|
|
|
|
// Out-of-office > Availability&Call&Meeting
|
|
[IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::MESSAGE_OUT_OF_OFFICE, false],
|
|
[IUserStatus::MESSAGE_CALENDAR_BUSY, IUserStatus::MESSAGE_OUT_OF_OFFICE, false],
|
|
[IUserStatus::MESSAGE_CALL, IUserStatus::MESSAGE_OUT_OF_OFFICE, false],
|
|
[IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::MESSAGE_AVAILABILITY, true],
|
|
[IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::MESSAGE_CALENDAR_BUSY, true],
|
|
[IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::MESSAGE_CALL, true],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider dataSetUserStatus
|
|
*/
|
|
public function testSetUserStatus(string $messageId, string $oldMessageId, bool $expectedUpdateShortcut): void {
|
|
$previous = new UserStatus();
|
|
$previous->setId(1);
|
|
$previous->setStatus(IUserStatus::AWAY);
|
|
$previous->setStatusTimestamp(1337);
|
|
$previous->setIsUserDefined(false);
|
|
$previous->setMessageId($oldMessageId);
|
|
$previous->setUserId('john');
|
|
$previous->setIsBackup(false);
|
|
|
|
$this->mapper->expects($this->once())
|
|
->method('findByUserId')
|
|
->with('john')
|
|
->willReturn($previous);
|
|
|
|
$e = DbalException::wrap($this->createMock(UniqueConstraintViolationException::class));
|
|
$this->mapper->expects($expectedUpdateShortcut ? $this->never() : $this->once())
|
|
->method('createBackupStatus')
|
|
->willThrowException($e);
|
|
|
|
$this->mapper->expects($this->any())
|
|
->method('update')
|
|
->willReturnArgument(0);
|
|
|
|
$this->predefinedStatusService->expects($this->once())
|
|
->method('isValidId')
|
|
->with($messageId)
|
|
->willReturn(true);
|
|
|
|
$this->service->setUserStatus('john', IUserStatus::DND, $messageId, true);
|
|
}
|
|
}
|