* [ADD] Unit testing. Work in progress

* [MOD] Code refactoring
This commit is contained in:
nuxsmin
2018-07-09 01:01:09 +02:00
parent a97b92131f
commit f764ebbb1e
8 changed files with 402 additions and 99 deletions

View File

@@ -66,7 +66,7 @@ class AuthTokenRepository extends Repository implements RepositoryItemInterface
*
* @param int $id
*
* @return AuthTokenData
* @return QueryResult
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
@@ -78,6 +78,7 @@ class AuthTokenRepository extends Repository implements RepositoryItemInterface
actionId,
createdBy,
startDate,
vault,
token,
`hash`
FROM AuthToken
@@ -88,7 +89,7 @@ class AuthTokenRepository extends Repository implements RepositoryItemInterface
$queryData->setQuery($query);
$queryData->addParam($id);
return $this->db->doSelect($queryData)->getData();
return $this->db->doSelect($queryData);
}
/**
@@ -431,7 +432,7 @@ class AuthTokenRepository extends Repository implements RepositoryItemInterface
public function getTokenByToken($actionId, $token)
{
$query = /** @lang SQL */
'SELECT id, actionId, userId, vault, `hash`
'SELECT id, actionId, userId, vault, `hash`, token
FROM AuthToken
WHERE actionId = ?
AND token = ? LIMIT 1';

View File

@@ -48,7 +48,6 @@ use SP\Services\Config\ConfigService;
use SP\Services\Service;
use SP\Services\ServiceException;
use SP\Services\ServiceItemTrait;
use SP\Storage\Database\Database;
use SP\Storage\Database\QueryResult;
/**
@@ -284,36 +283,23 @@ class AccountService extends Service implements AccountServiceInterface
*
* @param AccountRequest $accountRequest
*
* @throws ServiceException
* @throws \Exception
*/
public function update(AccountRequest $accountRequest)
{
$database = $this->dic->get(Database::class);
$this->transactionAware(function () use ($accountRequest) {
$accountRequest->changePermissions = AccountAclService::getShowPermission($this->context->getUserData(), $this->context->getUserProfile());
if ($database->beginTransaction()) {
try {
$accountRequest->changePermissions = AccountAclService::getShowPermission($this->context->getUserData(), $this->context->getUserProfile());
// Cambiar el grupo principal si el usuario es Admin
$accountRequest->changeUserGroup = ($accountRequest->userGroupId !== 0
&& ($this->context->getUserData()->getIsAdminApp() || $this->context->getUserData()->getIsAdminAcc()));
// Cambiar el grupo principal si el usuario es Admin
$accountRequest->changeUserGroup = ($accountRequest->userGroupId !== 0
&& ($this->context->getUserData()->getIsAdminApp() || $this->context->getUserData()->getIsAdminAcc()));
$this->addHistory($accountRequest->id);
$this->addHistory($accountRequest->id);
$this->accountRepository->update($accountRequest);
$this->accountRepository->update($accountRequest);
$this->updateItems($accountRequest);
$database->endTransaction();
} catch (\Exception $e) {
$database->rollbackTransaction();
throw $e;
}
} else {
throw new ServiceException(__u('No es posible iniciar una transacción'));
}
$this->updateItems($accountRequest);
}, $this->dic);
}
/**
@@ -393,33 +379,20 @@ class AccountService extends Service implements AccountServiceInterface
/**
* @param AccountRequest $accountRequest
*
* @throws ServiceException
* @throws \Exception
*/
public function editPassword(AccountRequest $accountRequest)
{
$database = $this->dic->get(Database::class);
$this->transactionAware(function () use ($accountRequest) {
$this->addHistory($accountRequest->id);
if ($database->beginTransaction()) {
try {
$this->addHistory($accountRequest->id);
$pass = $this->getPasswordEncrypted($accountRequest->pass);
$pass = $this->getPasswordEncrypted($accountRequest->pass);
$accountRequest->pass = $pass['pass'];
$accountRequest->key = $pass['key'];
$accountRequest->pass = $pass['pass'];
$accountRequest->key = $pass['key'];
$this->accountRepository->editPassword($accountRequest);
$database->endTransaction();
} catch (\Exception $e) {
$database->rollbackTransaction();
throw $e;
}
} else {
throw new ServiceException(__u('No es posible iniciar una transacción'));
}
$this->accountRepository->editPassword($accountRequest);
}, $this->dic);
}
/**
@@ -440,30 +413,17 @@ class AccountService extends Service implements AccountServiceInterface
* @param $historyId
* @param $accountId
*
* @throws ServiceException
* @throws \Exception
*/
public function editRestore($historyId, $accountId)
{
$database = $this->dic->get(Database::class);
$this->transactionAware(function () use ($historyId, $accountId) {
$this->addHistory($accountId);
if ($database->beginTransaction()) {
try {
$this->addHistory($accountId);
if (!$this->accountRepository->editRestore($historyId, $this->context->getUserData()->getId())) {
throw new ServiceException(__u('Error al restaurar cuenta'));
}
$database->endTransaction();
} catch (\Exception $e) {
$database->rollbackTransaction();
throw $e;
if (!$this->accountRepository->editRestore($historyId, $this->context->getUserData()->getId())) {
throw new ServiceException(__u('Error al restaurar cuenta'));
}
} else {
throw new ServiceException(__u('No es posible iniciar una transacción'));
}
}, $this->dic);
}
/**

View File

@@ -33,6 +33,7 @@ use SP\Core\Exceptions\SPException;
use SP\DataModel\AuthTokenData;
use SP\DataModel\ItemSearchData;
use SP\Repositories\AuthToken\AuthTokenRepository;
use SP\Repositories\NoSuchItemException;
use SP\Services\Service;
use SP\Services\ServiceException;
use SP\Services\ServiceItemTrait;
@@ -103,27 +104,27 @@ class AuthTokenService extends Service
/**
* @param $id
*
* @return mixed
* @return AuthTokenData
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function getById($id)
{
return $this->authTokenRepository->getById($id);
return $this->authTokenRepository->getById($id)->getData();
}
/**
* @param $id
*
* @return AuthTokenService
* @throws SPException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws NoSuchItemException
*/
public function delete($id)
{
if ($this->authTokenRepository->delete($id) === 0) {
throw new SPException(__u('Token no encontrado'), SPException::INFO);
throw new NoSuchItemException(__u('Token no encontrado'));
}
return $this;
@@ -220,6 +221,11 @@ class AuthTokenService extends Service
*/
private function getSecureData($token, $key)
{
if (($mKey = $this->context->getTrasientKey('_masterpass')) !== null) {
return (new Vault())
->saveData($mKey, $key . $token);
}
return (new Vault())
->saveData(CryptSession::getSessionKey($this->context), $key . $token);
}
@@ -227,29 +233,25 @@ class AuthTokenService extends Service
/**
* @param AuthTokenData $itemData
*
* @return mixed
* @throws SPException
* @throws \Defuse\Crypto\Exception\CryptoException
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \Exception
*/
public function refreshAndUpdate(AuthTokenData $itemData)
{
$token = $this->generateToken();
$vault = serialize($this->getSecureData($token, $itemData->getHash()));
$this->transactionAware(function () use ($itemData) {
$token = $this->generateToken();
$vault = serialize($this->getSecureData($token, $itemData->getHash()));
$this->authTokenRepository->refreshTokenByUserId($itemData->getUserId(), $token);
$this->authTokenRepository->refreshVaultByUserId($itemData->getUserId(), $vault, Hash::hashKey($itemData->getHash()));
$this->authTokenRepository->refreshTokenByUserId($itemData->getUserId(), $token);
$this->authTokenRepository->refreshVaultByUserId($itemData->getUserId(), $vault, Hash::hashKey($itemData->getHash()));
return $this->update($itemData, $token);
$this->update($itemData, $token);
}, $this->dic);
}
/**
* @param AuthTokenData $itemData
* @param string $token
*
* @return mixed
* @throws SPException
* @throws \Defuse\Crypto\Exception\CryptoException
* @throws \SP\Core\Exceptions\ConstraintException
@@ -257,7 +259,9 @@ class AuthTokenService extends Service
*/
public function update(AuthTokenData $itemData, $token = null)
{
return $this->authTokenRepository->update($this->injectSecureData($itemData, $token));
if ($this->authTokenRepository->update($this->injectSecureData($itemData, $token)) === 0) {
throw new NoSuchItemException(__u('Token no encontrado'));
}
}
/**

View File

@@ -56,7 +56,7 @@ class Installer extends Service
*/
const VERSION = [3, 0, 0];
const VERSION_TEXT = '3.0-beta';
const BUILD = 18070201;
const BUILD = 18070901;
/**
* @var ConfigService

View File

@@ -2,8 +2,8 @@
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
@@ -24,8 +24,10 @@
namespace SP\Services;
use DI\Container;
use SP\Bootstrap;
use SP\DataModel\DataModelInterface;
use SP\Storage\Database\Database;
/**
* Trait ServiceItemTrait
@@ -52,4 +54,37 @@ trait ServiceItemTrait
* @return mixed
*/
abstract public function getAllBasic();
/**
* Bubbles a Closure in a database transaction
*
* @param \Closure $closure
* @param Container $container
*
* @return mixed
* @throws ServiceException
* @throws \Exception
*/
private function transactionAware(\Closure $closure, Container $container)
{
$database = $container->get(Database::class);
if ($database->beginTransaction()) {
try {
$result = $closure->call($this);
$database->endTransaction();
return $result;
} catch (\Exception $e) {
$database->rollbackTransaction();
debugLog('Rollback');
throw $e;
}
} else {
throw new ServiceException(__u('No es posible iniciar una transacción'));
}
}
}

View File

@@ -77,21 +77,27 @@ class AuthTokenRepositoryTest extends DatabaseTestCase
*/
public function testGetById()
{
$authToken = self::$repository->getById(1);
$result = self::$repository->getById(1);
$this->assertEquals(1, $result->getNumRows());
$this->assertInstanceOf(AuthTokenData::class, $authToken);
$this->assertEquals(1, $authToken->getId());
$this->assertEquals(ActionsInterface::ACCOUNT_SEARCH, $authToken->getActionId());
$this->assertEquals(self::AUTH_TOKEN, $authToken->getToken());
$this->assertNull($authToken->getHash());
$data = $result->getData();
$authToken = self::$repository->getById(2);
$this->assertInstanceOf(AuthTokenData::class, $data);
$this->assertEquals(1, $data->getId());
$this->assertEquals(ActionsInterface::ACCOUNT_SEARCH, $data->getActionId());
$this->assertEquals(self::AUTH_TOKEN, $data->getToken());
$this->assertNull($data->getHash());
$this->assertInstanceOf(AuthTokenData::class, $authToken);
$this->assertEquals(2, $authToken->getId());
$this->assertEquals(ActionsInterface::ACCOUNT_VIEW_PASS, $authToken->getActionId());
$this->assertEquals(self::AUTH_TOKEN, $authToken->getToken());
$this->assertTrue(Hash::checkHashKey(self::AUTH_TOKEN_PASS, $authToken->getHash()));
$result = self::$repository->getById(2);
$this->assertEquals(1, $result->getNumRows());
$data = $result->getData();
$this->assertInstanceOf(AuthTokenData::class, $data);
$this->assertEquals(2, $data->getId());
$this->assertEquals(ActionsInterface::ACCOUNT_VIEW_PASS, $data->getActionId());
$this->assertEquals(self::AUTH_TOKEN, $data->getToken());
$this->assertTrue(Hash::checkHashKey(self::AUTH_TOKEN_PASS, $data->getHash()));
}
/**
@@ -211,7 +217,7 @@ class AuthTokenRepositoryTest extends DatabaseTestCase
$data = $result->getData();
$this->assertEquals(1, $result->getNumRows());
$this->assertInstanceOf(AuthTokenData::class, $result);
$this->assertInstanceOf(AuthTokenData::class, $data);
$this->assertEquals(ActionsInterface::ACCOUNT_CREATE, $data->getActionId());
$this->assertEquals($hash, $data->getHash());
$this->assertEquals(2, $data->getUserId());
@@ -324,7 +330,7 @@ class AuthTokenRepositoryTest extends DatabaseTestCase
$data = $result->getData();
$this->assertEquals(1, $result->getNumRows());
$this->assertInstanceOf(AuthTokenData::class, $result);
$this->assertInstanceOf(AuthTokenData::class, $data);
$this->assertEquals(ActionsInterface::ACCOUNT_CREATE, $data->getActionId());
$this->assertEquals($hash, $data->getHash());
$this->assertEquals(3, $data->getId());

View File

@@ -44,7 +44,7 @@ class ApiRequestTest extends TestCase
$apiRequest = new ApiRequest(getResource('json', 'account_search.json'));
$this->assertEquals(10, $apiRequest->getId());
$this->assertEquals('account/search', $apiRequest->getMethod());
$this->assertEquals('ce4e5f2e5700d9032b0cbb0769a6d7cf8557484da492d3c32626a74bb28fb44b', $apiRequest->get('authToken'));
$this->assertEquals('2cee8b224f48e01ef48ac172e879cc7825800a9d7ce3b23783212f4758f1c146', $apiRequest->get('authToken'));
$this->assertEquals('API', $apiRequest->get('text'));
$this->assertEquals(5, $apiRequest->get('count'));
$this->assertEquals(1, $apiRequest->get('clientId'));

View File

@@ -0,0 +1,297 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Tests\Services\AuthToken;
use Defuse\Crypto\Exception\CryptoException;
use SP\Core\Acl\ActionsInterface;
use SP\Core\Crypt\Hash;
use SP\Core\Crypt\Vault;
use SP\DataModel\AuthTokenData;
use SP\DataModel\ItemSearchData;
use SP\Repositories\DuplicatedItemException;
use SP\Repositories\NoSuchItemException;
use SP\Services\AuthToken\AuthTokenService;
use SP\Services\ServiceException;
use SP\Storage\Database\DatabaseConnectionData;
use SP\Tests\DatabaseTestCase;
use SP\Util\Util;
use function SP\Tests\setupContext;
/**
* Class AuthTokenServiceTest
*
* @package SP\Tests\Services\AuthToken
*/
class AuthTokenServiceTest extends DatabaseTestCase
{
const AUTH_TOKEN = '2cee8b224f48e01ef48ac172e879cc7825800a9d7ce3b23783212f4758f1c146';
const AUTH_TOKEN_PASS = 123456;
/**
* @var AuthTokenService
*/
private static $service;
/**
* @throws \DI\NotFoundException
* @throws \SP\Core\Context\ContextException
* @throws \DI\DependencyException
*/
public static function setUpBeforeClass()
{
$dic = setupContext();
self::$dataset = 'syspass_authToken.xml';
// Datos de conexión a la BBDD
self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
// Inicializar el servicio
self::$service = $dic->get(AuthTokenService::class);
}
/**
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testDelete()
{
self::$service->delete(1);
$this->expectException(NoSuchItemException::class);
self::$service->delete(10);
$this->assertEquals(4, $this->conn->getRowCount('AuthToken'));
}
/**
* @throws ServiceException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testDeleteByIdBatch()
{
$this->assertEquals(2, self::$service->deleteByIdBatch([1, 2]));
$this->assertEquals(0, self::$service->deleteByIdBatch([]));
$this->expectException(ServiceException::class);
self::$service->deleteByIdBatch([3, 10]);
$this->assertEquals(2, $this->conn->getRowCount('AuthToken'));
}
/**
* @throws \Exception
*/
public function testRefreshAndUpdate()
{
$data = new AuthTokenData();
$data->setId(1);
$data->setActionId(ActionsInterface::ACCOUNT_CREATE);
$data->setCreatedBy(1);
$data->setHash(self::AUTH_TOKEN_PASS);
$data->setUserId(2);
self::$service->refreshAndUpdate($data);
$resultData = self::$service->getById(1);
$vault = Util::unserialize(Vault::class, $resultData->getVault());
$this->assertEquals('12345678900', $vault->getData(self::AUTH_TOKEN_PASS . $resultData->getToken()));
$this->expectException(NoSuchItemException::class);
$data->setId(10);
$data->setActionId(ActionsInterface::ACCOUNT_DELETE);
$this->assertEquals(0, self::$service->refreshAndUpdate($data));
}
/**
* @throws ServiceException
* @throws \Defuse\Crypto\Exception\CryptoException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testGetTokenByToken()
{
$data = self::$service->getTokenByToken(ActionsInterface::ACCOUNT_VIEW_PASS, self::AUTH_TOKEN);
$this->assertInstanceOf(AuthTokenData::class, $data);
$this->assertEquals(2, $data->getId());
$this->assertEquals(ActionsInterface::ACCOUNT_VIEW_PASS, $data->getActionId());
$this->assertTrue(Hash::checkHashKey(self::AUTH_TOKEN_PASS, $data->getHash()));
$this->assertNotEmpty($data->getVault());
/** @var Vault $vault */
$vault = Util::unserialize(Vault::class, $data->getVault());
$this->assertEquals('12345678900', $vault->getData(self::AUTH_TOKEN_PASS . self::AUTH_TOKEN));
$this->expectException(CryptoException::class);
$vault->getData(1234);
}
/**
* @throws CryptoException
* @throws ServiceException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testUpdate()
{
$data = new AuthTokenData();
$data->setId(1);
$data->setActionId(ActionsInterface::ACCOUNT_CREATE);
$data->setCreatedBy(1);
$data->setHash(self::AUTH_TOKEN_PASS);
$data->setUserId(2);
self::$service->update($data);
$data = self::$service->getTokenByToken(ActionsInterface::ACCOUNT_CREATE, $data->getToken());
$this->assertInstanceOf(AuthTokenData::class, $data);
$this->assertEquals(ActionsInterface::ACCOUNT_CREATE, $data->getActionId());
$this->assertTrue(Hash::checkHashKey(self::AUTH_TOKEN_PASS, $data->getHash()));
$this->assertEquals(2, $data->getUserId());
$vault = Util::unserialize(Vault::class, $data->getVault());
$this->assertEquals('12345678900', $vault->getData(self::AUTH_TOKEN_PASS . $data->getToken()));
$this->expectException(NoSuchItemException::class);
$data->setId(10);
$data->setUserId(1);
self::$service->update($data);
}
/**
* @throws CryptoException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testGetById()
{
$data = self::$service->getById(1);
$this->assertInstanceOf(AuthTokenData::class, $data);
$this->assertEquals(1, $data->getId());
$this->assertEquals(ActionsInterface::ACCOUNT_SEARCH, $data->getActionId());
$this->assertEquals(pack('H*', '31326239303237643234656666663762666261636138626437373461346333346234356465333565303333643262313932613838663464666165653563323333'), $data->getToken());
$this->assertNull($data->getHash());
$data = self::$service->getById(2);
$this->assertInstanceOf(AuthTokenData::class, $data);
$this->assertEquals(2, $data->getId());
$this->assertEquals(ActionsInterface::ACCOUNT_VIEW_PASS, $data->getActionId());
$this->assertEquals(self::AUTH_TOKEN, $data->getToken());
$this->assertTrue(Hash::checkHashKey(self::AUTH_TOKEN_PASS, $data->getHash()));
$vault = Util::unserialize(Vault::class, $data->getVault());
$this->assertEquals('12345678900', $vault->getData(self::AUTH_TOKEN_PASS . $data->getToken()));
}
/**
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testSearch()
{
$itemSearchData = new ItemSearchData();
$itemSearchData->setSeachString('admin');
$result = self::$service->search($itemSearchData);
$data = $result->getDataAsArray();
$this->assertEquals(4, $result->getNumRows());
$this->assertCount(4, $data);
$this->assertInstanceOf(\stdClass::class, $data[0]);
$this->assertEquals(ActionsInterface::ACCOUNT_SEARCH, $data[0]->actionId);
$this->assertEquals(self::AUTH_TOKEN, $data[0]->token);
$this->assertInstanceOf(\stdClass::class, $data[1]);
$this->assertEquals(ActionsInterface::ACCOUNT_VIEW, $data[1]->actionId);
$this->assertEquals(self::AUTH_TOKEN, $data[1]->token);
$itemSearchData = new ItemSearchData();
$itemSearchData->setSeachString('test');
$result = self::$service->search($itemSearchData);
$this->assertEquals(0, $result->getNumRows());
$this->assertCount(0, $result->getDataAsArray());
}
/**
* @throws CryptoException
* @throws ServiceException
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testCreate()
{
$authTokenData = new AuthTokenData();
$authTokenData->setActionId(ActionsInterface::ACCOUNT_CREATE);
$authTokenData->setCreatedBy(1);
$authTokenData->setHash(self::AUTH_TOKEN_PASS);
$authTokenData->setUserId(2);
$this->assertEquals(6, self::$service->create($authTokenData));
$this->assertEquals(6, $this->conn->getRowCount('AuthToken'));
$data = self::$service->getTokenByToken(ActionsInterface::ACCOUNT_CREATE, $authTokenData->getToken());
$this->assertInstanceOf(AuthTokenData::class, $data);
$this->assertEquals(ActionsInterface::ACCOUNT_CREATE, $data->getActionId());
$this->assertTrue(Hash::checkHashKey(self::AUTH_TOKEN_PASS, $data->getHash()));
$this->assertEquals(6, $data->getId());
$this->assertEquals(2, $data->getUserId());
$vault = Util::unserialize(Vault::class, $data->getVault());
$this->assertEquals('12345678900', $vault->getData(self::AUTH_TOKEN_PASS . $data->getToken()));
$this->expectException(DuplicatedItemException::class);
$authTokenData->setUserId(2);
self::$service->create($authTokenData);
}
}