Rework tests structure. Upgrade codeception to 2.5.3. Merge params configuration into app configuration.

This commit is contained in:
ErickSkrauch
2019-02-20 22:58:52 +03:00
parent 2eacc581be
commit b05dc6816e
248 changed files with 1503 additions and 1339 deletions

View File

@@ -0,0 +1,21 @@
namespace: common\tests
actor_suffix: Tester
paths:
tests: tests
log: tests/_output
data: tests/_data
helpers: tests/_support
settings:
bootstrap: _bootstrap.php
colors: true
memory_limit: 1024M
coverage:
enabled: true
whitelist:
include:
- ./*
exclude:
- config/*
- mail/*
- codeception.dist.yml
- codeception.yml

View File

@@ -1,4 +1,6 @@
<?php
declare(strict_types=1);
namespace common\config;
use yii\helpers\ArrayHelper;

View File

@@ -1,4 +1,3 @@
<?php
Yii::setAlias('common', dirname(__DIR__));
Yii::setAlias('api', dirname(__DIR__, 2) . '/api');
Yii::setAlias('console', dirname(__DIR__, 2) . '/console');
// Do not use Yii2 autoloader and left it to the composer
spl_autoload_unregister(['Yii', 'autoload']);

View File

@@ -0,0 +1,23 @@
<?php
return [
'id' => 'common-tests',
'basePath' => dirname(__DIR__),
'params' => [
'fromEmail' => 'ely@ely.by',
],
'components' => [
'security' => [
// It's allows us to increase tests speed by decreasing password hashing algorithm complexity
'passwordHashCost' => 4,
],
'queue' => [
'class' => common\tests\_support\queue\Queue::class,
],
'sentry' => [
'enabled' => false,
],
'mailer' => [
'useFileTransport' => true,
],
],
];

View File

@@ -2,6 +2,24 @@
return [
'version' => '{{PLACE_VERSION_HERE}}', // This will be replaced by build tool
'vendorPath' => dirname(__DIR__, 2) . '/vendor',
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
'@root' => dirname(__DIR__, 2),
'@api' => '@root/api',
'@common' => '@root/common',
'@console' => '@root/console',
],
'params' => [
'fromEmail' => 'ely@ely.by',
'supportEmail' => 'support@ely.by',
],
'container' => [
'definitions' => [
GuzzleHttp\ClientInterface::class => GuzzleHttp\Client::class,
],
],
'components' => [
'cache' => [
'class' => yii\redis\Cache::class,
@@ -91,13 +109,4 @@ return [
'class' => yii\queue\redis\Queue::class,
],
],
'container' => [
'definitions' => [
GuzzleHttp\ClientInterface::class => GuzzleHttp\Client::class,
],
],
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
];

View File

@@ -1,5 +0,0 @@
<?php
return [
'fromEmail' => 'ely@ely.by',
'supportEmail' => 'support@ely.by',
];

2
common/tests/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
unit.suite.yml
_support/_generated

View File

@@ -0,0 +1,8 @@
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'test');
defined('YII_APP_BASE_PATH') or define('YII_APP_BASE_PATH', __DIR__ . '/../../');
require_once __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/../../vendor/yiisoft/yii2/Yii.php';
require __DIR__ . '/../config/bootstrap.php';

2
common/tests/_output/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*
!.gitignore

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace common\tests\_support;
use Codeception\Exception\ModuleConfigException;
use Codeception\Module;
use Yii;
class ApplicationRedisBridge extends Module {
protected $config = [
'module' => 'Redis',
];
public function _initialize(): void {
if (!$this->hasModule($this->config['module'])) {
throw new ModuleConfigException($this, 'This module should be used together with Redis module');
}
/** @var \Codeception\Module\Redis $module */
$module = $this->getModule($this->config['module']);
$config = $module->_getConfig();
$config['host'] = Yii::$app->redis->hostname;
$config['port'] = Yii::$app->redis->port;
$config['database'] = Yii::$app->redis->database;
$module->_setConfig($config);
if ($module->driver !== null) {
$module->_initialize();
}
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace common\tests\_support;
use Codeception\Module;
use Codeception\TestInterface;
use common\tests\fixtures\AccountFixture;
use common\tests\fixtures\AccountSessionFixture;
use common\tests\fixtures\EmailActivationFixture;
use common\tests\fixtures\MinecraftAccessKeyFixture;
use common\tests\fixtures\OauthClientFixture;
use common\tests\fixtures\OauthSessionFixture;
use common\tests\fixtures\UsernameHistoryFixture;
use yii\test\FixtureTrait;
use yii\test\InitDbFixture;
/**
* This helper is used to populate the database with needed fixtures before any tests are run.
* All fixtures will be loaded before the suite is started and unloaded after it completes.
*
* TODO: try to remove
*/
class FixtureHelper extends Module {
/**
* Redeclare visibility because codeception includes all public methods that do not start with "_"
* and are not excluded by module settings, in actor class.
*/
use FixtureTrait {
loadFixtures as protected;
fixtures as protected;
globalFixtures as protected;
unloadFixtures as protected;
getFixtures as protected;
getFixture as protected;
}
public function _before(TestInterface $test) {
$this->loadFixtures();
}
public function _after(TestInterface $test) {
$this->unloadFixtures();
}
public function globalFixtures() {
return [
InitDbFixture::class,
];
}
public function fixtures() {
return [
'accounts' => AccountFixture::class,
'accountSessions' => AccountSessionFixture::class,
'emailActivations' => EmailActivationFixture::class,
'usernamesHistory' => UsernameHistoryFixture::class,
'oauthClients' => OauthClientFixture::class,
'oauthSessions' => OauthSessionFixture::class,
'minecraftAccessKeys' => MinecraftAccessKeyFixture::class,
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace common\tests\_support;
use Codeception\Module;
use Codeception\TestInterface;
class Mockery extends Module {
/**
* @var bool Run mockery expectations after test or not
*/
private $assert_mocks = true;
public function _before(TestInterface $test) {
\Mockery::globalHelpers();
}
public function _after(TestInterface $test) {
if ($this->assert_mocks) {
\Mockery::close();
} else {
\Mockery::getContainer()->mockery_close();
\Mockery::resetContainer();
}
}
public function _failed(TestInterface $test, $fail) {
$this->assert_mocks = false;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace common\tests\_support;
use ReflectionClass;
trait ProtectedCaller {
protected function callProtected($object, string $function, ...$args) {
$class = new ReflectionClass($object);
$method = $class->getMethod($function);
$method->setAccessible(true);
return $method->invokeArgs($object, $args);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace common\tests;
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class UnitTester extends \Codeception\Actor {
use _generated\UnitTesterActions;
/**
* Define custom actions here
*/
}

View File

@@ -0,0 +1,56 @@
<?php
namespace common\tests\_support\queue;
use Codeception\Exception\ModuleException;
use Codeception\Module;
use Codeception\Module\Yii2;
class CodeceptionQueueHelper extends Module {
/**
* Returns last sent message
*
* @return \yii\queue\JobInterface|null
*/
public function grabLastQueuedJob() {
$messages = $this->grabQueueJobs();
$last = end($messages);
if ($last === false) {
return null;
}
return $last;
}
/**
* Returns array of all sent amqp messages.
* Each message is `\PhpAmqpLib\Message\AMQPMessage` instance.
* Useful to perform additional checks using `Asserts` module.
*
* @param string|null $exchange
* @return \yii\queue\JobInterface[]
* @throws ModuleException
*/
public function grabQueueJobs() {
$amqp = $this->grabComponent('queue');
if (!$amqp instanceof Queue) {
throw new ModuleException($this, 'AMQP module is not mocked, can\'t test messages');
}
return $amqp->getMessages();
}
private function grabComponent(string $component) {
return $this->getYii2()->grabComponent($component);
}
private function getYii2(): Yii2 {
$yii2 = $this->getModule('Yii2');
if (!$yii2 instanceof Yii2) {
throw new ModuleException($this, 'Yii2 module must be configured');
}
return $yii2;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace common\tests\_support\queue;
use yii\base\NotSupportedException;
use yii\queue\Queue as BaseQueue;
class Queue extends BaseQueue {
private $messages = [];
public function __set($name, $value) {
// Yii2 components may contains some configuration
// But we just ignore it for this mock component
}
public function push($job) {
$this->messages[] = $job;
}
public function status($id) {
throw new NotSupportedException('Status is not supported in the driver.');
}
public function getMessages() {
return $this->messages;
}
protected function pushMessage($message, $ttr, $delay, $priority) {
// This function is abstract, but will be not called
}
}

View File

@@ -0,0 +1,8 @@
<?php
use common\config\ConfigLoader;
use yii\helpers\ArrayHelper;
return ArrayHelper::merge(ConfigLoader::load('common'), [
]);

View File

@@ -0,0 +1,13 @@
<?php
namespace common\tests\fixtures;
use common\models\Account;
use yii\test\ActiveFixture;
class AccountFixture extends ActiveFixture {
public $modelClass = Account::class;
public $dataFile = '@root/common/tests/fixtures/data/accounts.php';
}

View File

@@ -0,0 +1,17 @@
<?php
namespace common\tests\fixtures;
use common\models\AccountSession;
use yii\test\ActiveFixture;
class AccountSessionFixture extends ActiveFixture {
public $modelClass = AccountSession::class;
public $dataFile = '@root/common/tests/fixtures/data/account-sessions.php';
public $depends = [
AccountFixture::class,
];
}

View File

@@ -0,0 +1,17 @@
<?php
namespace common\tests\fixtures;
use common\models\EmailActivation;
use yii\test\ActiveFixture;
class EmailActivationFixture extends ActiveFixture {
public $modelClass = EmailActivation::class;
public $dataFile = '@root/common/tests/fixtures/data/email-activations.php';
public $depends = [
AccountFixture::class,
];
}

View File

@@ -0,0 +1,17 @@
<?php
namespace common\tests\fixtures;
use common\models\MinecraftAccessKey;
use yii\test\ActiveFixture;
class MinecraftAccessKeyFixture extends ActiveFixture {
public $modelClass = MinecraftAccessKey::class;
public $dataFile = '@root/common/tests/fixtures/data/minecraft-access-keys.php';
public $depends = [
AccountFixture::class,
];
}

View File

@@ -0,0 +1,13 @@
<?php
namespace common\tests\fixtures;
use common\models\MojangUsername;
use yii\test\ActiveFixture;
class MojangUsernameFixture extends ActiveFixture {
public $modelClass = MojangUsername::class;
public $dataFile = '@root/common/tests/fixtures/data/mojang-usernames.php';
}

View File

@@ -0,0 +1,17 @@
<?php
namespace common\tests\fixtures;
use common\models\OauthClient;
use yii\test\ActiveFixture;
class OauthClientFixture extends ActiveFixture {
public $modelClass = OauthClient::class;
public $dataFile = '@root/common/tests/fixtures/data/oauth-clients.php';
public $depends = [
AccountFixture::class,
];
}

View File

@@ -0,0 +1,18 @@
<?php
namespace common\tests\fixtures;
use common\models\OauthSession;
use yii\test\ActiveFixture;
class OauthSessionFixture extends ActiveFixture {
public $modelClass = OauthSession::class;
public $dataFile = '@root/common/tests/fixtures/data/oauth-sessions.php';
public $depends = [
OauthClientFixture::class,
AccountFixture::class,
];
}

View File

@@ -0,0 +1,13 @@
<?php
namespace common\tests\fixtures;
use common\models\UsernameHistory;
use yii\test\ActiveFixture;
class UsernameHistoryFixture extends ActiveFixture {
public $modelClass = UsernameHistory::class;
public $dataFile = '@root/common/tests/fixtures/data/usernames-history.php';
}

View File

@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace common\tests\fixtures;
use common\models\WebHookEvent;
use yii\test\ActiveFixture;
class WebHooksEventsFixture extends ActiveFixture {
public $modelClass = WebHookEvent::class;
public $dataFile = '@root/common/tests/fixtures/data/webhooks-events.php';
public $depends = [
WebHooksFixture::class,
];
}

View File

@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace common\tests\fixtures;
use common\models\WebHook;
use yii\test\ActiveFixture;
class WebHooksFixture extends ActiveFixture {
public $modelClass = WebHook::class;
public $dataFile = '@root/common/tests/fixtures/data/webhooks.php';
}

View File

@@ -0,0 +1,43 @@
<?php
return [
'admin' => [
'id' => 1,
'account_id' => 1,
'refresh_token' => 'SOutIr6Seeaii3uqMVy3Wan8sKFVFrNz',
'last_used_ip' => ip2long('127.0.0.1'),
'created_at' => time(),
'last_refreshed_at' => time(),
],
'admin2' => [
'id' => 2,
'account_id' => 1,
'refresh_token' => 'RI5CdxTama2ZijwYw03rJAq84M2JzPM3gDeIDGI8',
'last_used_ip' => ip2long('136.243.88.97'),
'created_at' => time(),
'last_refreshed_at' => time(),
],
'banned-user-session' => [
'id' => 3,
'account_id' => 10,
'refresh_token' => 'Af7fIuV6eL61tRUHn40yhmDRXN1OQxKR',
'last_used_ip' => ip2long('182.123.234.123'),
'created_at' => time(),
'last_refreshed_at' => time(),
],
'very-expired-session' => [
'id' => 4,
'account_id' => 1,
'refresh_token' => 'dkzIbUdtVLU3LOotSofUU0BQTvClMqmiIGwVKz2VHXOENifj',
'last_used_ip' => ip2long('127.0.0.1'),
'created_at' => 1477414260,
'last_refreshed_at' => 1480092660,
],
'not-refreshed-session' => [
'id' => 5,
'account_id' => 1,
'refresh_token' => 'NM9g7fZyn1o3F87BkDtRCQaHLuudDxyuup3ttyDRIjmwPPJx',
'last_used_ip' => ip2long('127.0.0.1'),
'created_at' => time() - 1814400, // 3 weeks
'last_refreshed_at' => time() - 1814400, // 3 weeks
],
];

205
common/tests/fixtures/data/accounts.php vendored Normal file
View File

@@ -0,0 +1,205 @@
<?php
return [
'admin' => [
'id' => 1,
'uuid' => 'df936908-b2e1-544d-96f8-2977ec213022',
'username' => 'Admin',
'email' => 'admin@ely.by',
'password_hash' => '$2y$13$CXT0Rkle1EMJ/c1l5bylL.EylfmQ39O5JlHJVFpNn618OUS1HwaIi', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'created_at' => 1451775316,
'updated_at' => 1451775316,
'password_changed_at' => 1451775316,
],
'user-with-old-password-type' => [
'id' => 2,
'uuid' => 'bdc239f0-8a22-518d-8b93-f02d4827c3eb',
'username' => 'AccWithOldPassword',
'email' => 'erickskrauch123@yandex.ru',
'password_hash' => '133c00c463cbd3e491c28cb653ce4718', # 12345678
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_OLD_ELY,
'lang' => 'en',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'created_at' => 1385225069,
'updated_at' => 1385225069,
'password_changed_at' => 1385225069,
],
'not-activated-account' => [
'id' => 3,
'uuid' => '86c6fedb-bffc-37a5-8c0f-62e8fa9a2af7',
'username' => 'howe.garnett',
'email' => 'achristiansen@gmail.com',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'status' => \common\models\Account::STATUS_REGISTERED,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'created_at' => 1453146616,
'updated_at' => 1453146616,
'password_changed_at' => 1453146616,
],
'not-activated-account-with-expired-message' => [
'id' => 4,
'uuid' => '58a7bfdc-ad0f-44c3-9197-759cb9220895',
'username' => 'Jon',
'email' => 'jon@ely.by',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'status' => \common\models\Account::STATUS_REGISTERED,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'created_at' => 1457890086,
'updated_at' => 1457890086,
'password_changed_at' => 1457890086,
],
'account-with-fresh-forgot-password-message' => [
'id' => 5,
'uuid' => '4aaf4f00-3b5b-4d36-9252-9e8ee0c86679',
'username' => 'Notch',
'email' => 'notch@mojang.com',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'created_at' => 1462891432,
'updated_at' => 1462891432,
'password_changed_at' => 1462891432,
],
'account-with-expired-forgot-password-message' => [
'id' => 6,
'uuid' => '26187ae7-bc96-421f-9766-6517f8ee52b7',
'username' => '23derevo',
'email' => '23derevo@gmail.com',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'created_at' => 1462891612,
'updated_at' => 1462891612,
'password_changed_at' => 1462891612,
],
'account-with-change-email-init-state' => [
'id' => 7,
'uuid' => '7d728533-847a-4661-9bc7-3df01b2282ef',
'username' => 'ILLIMUNATI',
'email' => 'illuminati@gmail.com',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'created_at' => 1463427287,
'updated_at' => 1463427287,
'password_changed_at' => 1463427287,
],
'account-with-change-email-finish-state' => [
'id' => 8,
'uuid' => '4c34f2cc-4bd9-454b-9583-bb52f020ec16',
'username' => 'CrafterGameplays',
'email' => 'crafter@gmail.com',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'created_at' => 1463349615,
'updated_at' => 1463349615,
'password_changed_at' => 1463349615,
],
'account-with-old-rules-version' => [
'id' => 9,
'uuid' => '410462d3-8e71-47cc-bac6-64f77f88cf80',
'username' => 'Veleyaba',
'email' => 'veleyaba@gmail.com',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => null,
'created_at' => 1470499952,
'updated_at' => 1470499952,
'password_changed_at' => 1470499952,
],
'banned-account' => [
'id' => 10,
'uuid' => 'd2e7360e-50cf-4b9b-baa0-c4440a150795',
'username' => 'Banned',
'email' => 'banned@ely.by',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'status' => \common\models\Account::STATUS_BANNED,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'created_at' => 1472682343,
'updated_at' => 1472682343,
'password_changed_at' => 1472682343,
],
'account-with-usernames-history' => [
'id' => 11,
'uuid' => 'd6b3e935-6466-4cb8-86db-b5df91ae6541',
'username' => 'klik202',
'email' => 'klik202@mail.ru',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'ru',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'created_at' => 1474404139,
'updated_at' => 1474404149,
'password_changed_at' => 1474404149,
],
'account-with-otp-secret' => [
'id' => 12,
'uuid' => '9e9dcd11-2322-46dc-a992-e822a422726e',
'username' => 'AccountWithOtpSecret',
'email' => 'sava-galkin@mail.ru',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'ru',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'otp_secret' => 'AAAA',
'is_otp_enabled' => false,
'created_at' => 1485124615,
'updated_at' => 1485124615,
'password_changed_at' => 1485124615,
],
'account-with-enabled-otp' => [
'id' => 13,
'uuid' => '15d0afa7-a2bb-44d3-9f31-964cbccc6043',
'username' => 'AccountWithEnabledOtp',
'email' => 'otp@gmail.com',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'ru',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'otp_secret' => 'BBBB',
'is_otp_enabled' => true,
'created_at' => 1485124685,
'updated_at' => 1485124685,
'password_changed_at' => 1485124685,
],
'account-with-two-oauth-clients' => [
'id' => 14,
'uuid' => '1b946267-b1a9-4409-ae83-94f84a329883',
'username' => 'TwoOauthClients',
'email' => 'oauth2-two@gmail.com',
'password_hash' => '$2y$13$2rYkap5T6jG8z/mMK8a3Ou6aZxJcmAaTha6FEuujvHEmybSHRzW5e', # password_0
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'ru',
'status' => \common\models\Account::STATUS_ACTIVE,
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
'otp_secret' => null,
'is_otp_enabled' => false,
'created_at' => 1519487320,
'updated_at' => 1519487320,
'password_changed_at' => 1519487320,
],
];

View File

@@ -0,0 +1,46 @@
<?php
return [
'freshRegistrationConfirmation' => [
'key' => 'HABGCABHJ1234HBHVD',
'account_id' => 3,
'type' => \common\models\EmailActivation::TYPE_REGISTRATION_EMAIL_CONFIRMATION,
'created_at' => time(),
],
'oldRegistrationConfirmation' => [
'key' => 'H23HBDCHHAG2HGHGHS',
'account_id' => 4,
'type' => \common\models\EmailActivation::TYPE_REGISTRATION_EMAIL_CONFIRMATION,
'created_at' => time() - (new \common\models\confirmations\RegistrationConfirmation())->repeatTimeout - 10,
],
'freshPasswordRecovery' => [
'key' => 'H24HBDCHHAG2HGHGHS',
'account_id' => 5,
'type' => \common\models\EmailActivation::TYPE_FORGOT_PASSWORD_KEY,
'created_at' => time(),
],
'oldPasswordRecovery' => [
'key' => 'H25HBDCHHAG2HGHGHS',
'account_id' => 6,
'type' => \common\models\EmailActivation::TYPE_FORGOT_PASSWORD_KEY,
'created_at' => time() - (new \common\models\confirmations\ForgotPassword())->repeatTimeout - 10,
],
'currentChangeEmailConfirmation' => [
'key' => 'H27HBDCHHAG2HGHGHS',
'account_id' => 7,
'type' => \common\models\EmailActivation::TYPE_CURRENT_EMAIL_CONFIRMATION,
'created_at' => time() - 10,
],
'newEmailConfirmation' => [
'key' => 'H28HBDCHHAG2HGHGHS',
'account_id' => 8,
'type' => \common\models\EmailActivation::TYPE_NEW_EMAIL_CONFIRMATION,
'_data' => serialize(['newEmail' => 'my-new-email@ely.by']),
'created_at' => time() - 10,
],
'deeplyExpiredConfirmation' => [
'key' => 'H29HBDCHHAG2HGHGHS',
'account_id' => 1,
'type' => \common\models\EmailActivation::TYPE_NEW_EMAIL_CONFIRMATION,
'created_at' => 1487695872,
],
];

View File

@@ -0,0 +1,24 @@
<?php
return [
'admin-token' => [
'access_token' => 'e7bb6648-2183-4981-9b86-eba5e7f87b42',
'client_token' => '6f380440-0c05-47bd-b7c6-d011f1b5308f',
'account_id' => 1,
'created_at' => time() - 10,
'updated_at' => time() - 10,
],
'expired-token' => [
'access_token' => '6042634a-a1e2-4aed-866c-c661fe4e63e2',
'client_token' => '47fb164a-2332-42c1-8bad-549e67bb210c',
'account_id' => 1,
'created_at' => 1472423530,
'updated_at' => 1472423530,
],
'banned-token' => [
'access_token' => '918ecb41-616c-40ee-a7d2-0b0ef0d0d732',
'client_token' => '6042634a-a1e2-4aed-866c-c661fe4e63e2',
'account_id' => 10,
'created_at' => time() - 10,
'updated_at' => time() - 10,
],
];

View File

@@ -0,0 +1,23 @@
<?php
return [
'ErickSkrauch' => [
'username' => 'ErickSkrauch',
'uuid' => '3e3ee6c35afa48abb61e8cd8c42fc0d9',
'last_pulled_at' => 1461429129,
],
'Notch' => [
'username' => 'Notch',
'uuid' => '069a79f444e94726a5befca90e38aaf5',
'last_pulled_at' => 1461429207,
],
'not-exists' => [
'username' => '100_not_exists',
'uuid' => 'f8d4ac1fb24d423483d619832b5d475c',
'last_pulled_at' => 1461433981,
],
'uuid-changed' => [
'username' => 'jeb',
'uuid' => 'ef4c8352cecc417bbcae32f1f3e2828b',
'last_pulled_at' => 1461434315,
],
];

View File

@@ -0,0 +1,143 @@
<?php
return [
'ely' => [
'id' => 'ely',
'secret' => 'ZuM1vGchJz-9_UZ5HC3H3Z9Hg5PzdbkM',
'type' => 'application',
'name' => 'Ely.by',
'description' => 'Всем знакомое елуби',
'redirect_uri' => 'http://ely.by',
'website_url' => '',
'minecraft_server_ip' => '',
'account_id' => null,
'is_trusted' => 0,
'is_deleted' => 0,
'created_at' => 1455309271,
],
'tlauncher' => [
'id' => 'tlauncher',
'secret' => 'HsX-xXzdGiz3mcsqeEvrKHF47sqiaX94',
'type' => 'application',
'name' => 'TLauncher',
'description' => 'Лучший альтернативный лаунчер для Minecraft с большим количеством версий и их модификаций, а также возмоностью входа как с лицензионным аккаунтом, так и без него.',
'redirect_uri' => '',
'website_url' => '',
'minecraft_server_ip' => '',
'account_id' => null,
'is_trusted' => 0,
'is_deleted' => 0,
'created_at' => 1455318468,
],
'test1' => [
'id' => 'test1',
'secret' => 'eEvrKHF47sqiaX94HsX-xXzdGiz3mcsq',
'type' => 'application',
'name' => 'Test1',
'description' => 'Some description',
'redirect_uri' => 'http://test1.net',
'website_url' => '',
'minecraft_server_ip' => '',
'account_id' => null,
'is_trusted' => 0,
'is_deleted' => 0,
'created_at' => 1479937982,
],
'trustedClient' => [
'id' => 'trusted-client',
'secret' => 'tXBbyvMcyaOgHMOAXBpN2EC7uFoJAaL9',
'type' => 'application',
'name' => 'Trusted client',
'description' => 'Это клиент, которому мы доверяем',
'redirect_uri' => null,
'website_url' => '',
'minecraft_server_ip' => '',
'account_id' => null,
'is_trusted' => 1,
'is_deleted' => 0,
'created_at' => 1482922663,
],
'defaultClient' => [
'id' => 'default-client',
'secret' => 'AzWRy7ZjS1yRQUk2vRBDic8fprOKDB1W',
'type' => 'application',
'name' => 'Default client',
'description' => 'Это обычный клиент, каких может быть много',
'redirect_uri' => null,
'website_url' => '',
'minecraft_server_ip' => '',
'account_id' => null,
'is_trusted' => 0,
'is_deleted' => 0,
'created_at' => 1482922711,
],
'admin_oauth_client' => [
'id' => 'admin-oauth-client',
'secret' => 'FKyO71iCIlv4YM2IHlLbhsvYoIJScUzTZt1kEK7DQLXXYISLDvURVXK32Q58sHWS',
'type' => 'application',
'name' => 'Admin\'s oauth client',
'description' => 'Personal oauth client',
'redirect_uri' => 'http://some-site.com/oauth/ely',
'website_url' => '',
'minecraft_server_ip' => '',
'account_id' => 1,
'is_trusted' => 0,
'is_deleted' => 0,
'created_at' => 1519254133,
],
'first_test_oauth_client' => [
'id' => 'first-test-oauth-client',
'secret' => 'Zt1kEK7DQLXXYISLDvURVXK32Q58sHWSFKyO71iCIlv4YM2IHlLbhsvYoIJScUzT',
'type' => 'application',
'name' => 'First test oauth client',
'description' => 'Some description to the first oauth client',
'redirect_uri' => 'http://some-site-1.com/oauth/ely',
'website_url' => '',
'minecraft_server_ip' => '',
'account_id' => 14,
'is_trusted' => 0,
'is_deleted' => 0,
'created_at' => 1519487434,
],
'another_test_oauth_client' => [
'id' => 'another-test-oauth-client',
'secret' => 'URVXK32Q58sHWSFKyO71iCIlv4YM2Zt1kEK7DQLXXYISLDvIHlLbhsvYoIJScUzT',
'type' => 'minecraft-server',
'name' => 'Another test oauth client',
'description' => null,
'redirect_uri' => null,
'website_url' => '',
'minecraft_server_ip' => '136.243.88.97:25565',
'account_id' => 14,
'is_trusted' => 0,
'is_deleted' => 0,
'created_at' => 1519487472,
],
'deleted_oauth_client' => [
'id' => 'deleted-oauth-client',
'secret' => 'YISLDvIHlLbhsvYoIJScUzTURVXK32Q58sHWSFKyO71iCIlv4YM2Zt1kEK7DQLXX',
'type' => 'application',
'name' => 'Deleted OAuth Client',
'description' => null,
'redirect_uri' => 'http://not-exists-site.com/oauth/ely',
'website_url' => '',
'minecraft_server_ip' => null,
'account_id' => 1,
'is_trusted' => 0,
'is_deleted' => 1,
'created_at' => 1519504563,
],
'deleted_oauth_client_with_sessions' => [
'id' => 'deleted-oauth-client-with-sessions',
'secret' => 'EK7DQLXXYISLDvIHlLbhsvYoIJScUzTURVXK32Q58sHWSFKyO71iCIlv4YM2Zt1k',
'type' => 'application',
'name' => 'I still have some sessions ^_^',
'description' => null,
'redirect_uri' => 'http://not-exists-site.com/oauth/ely',
'website_url' => '',
'minecraft_server_ip' => null,
'account_id' => 1,
'is_trusted' => 0,
'is_deleted' => 1,
'created_at' => 1519507190,
],
];

View File

@@ -0,0 +1,35 @@
<?php
return [
'admin-test1' => [
'id' => 1,
'owner_type' => 'user',
'owner_id' => 1,
'client_id' => 'test1',
'client_redirect_uri' => 'http://test1.net/oauth',
'created_at' => 1479944472,
],
'banned-account-session' => [
'id' => 2,
'owner_type' => 'user',
'owner_id' => 10,
'client_id' => 'test1',
'client_redirect_uri' => 'http://test1.net/oauth',
'created_at' => 1481421663,
],
'deleted-client-session' => [
'id' => 3,
'owner_type' => 'user',
'owner_id' => 1,
'client_id' => 'deleted-oauth-client-with-sessions',
'client_redirect_uri' => 'http://not-exists-site.com/oauth/ely',
'created_at' => 1519510065,
],
'actual-deleted-client-session' => [
'id' => 4,
'owner_type' => 'user',
'owner_id' => 2,
'client_id' => 'deleted-oauth-client-with-sessions',
'client_redirect_uri' => 'http://not-exists-site.com/oauth/ely',
'created_at' => 1519511568,
],
];

View File

@@ -0,0 +1,27 @@
<?php
return [
[
'id' => 1,
'username' => 'Admin',
'account_id' => 1,
'applied_in' => 1451775316,
],
[
'id' => 2,
'username' => 'klik202',
'account_id' => 11,
'applied_in' => 1474404139,
],
[
'id' => 3,
'username' => 'klik201',
'account_id' => 11,
'applied_in' => 1474404141,
],
[
'id' => 4,
'username' => 'klik202',
'account_id' => 11,
'applied_in' => 1474404143,
],
];

View File

@@ -0,0 +1,11 @@
<?php
return [
[
'webhook_id' => 1,
'event_type' => 'account.edit',
],
[
'webhook_id' => 2,
'event_type' => 'account.edit',
],
];

21
common/tests/fixtures/data/webhooks.php vendored Normal file
View File

@@ -0,0 +1,21 @@
<?php
return [
'webhook-with-secret' => [
'id' => 1,
'url' => 'http://localhost:80/webhooks/ely',
'secret' => 'my-secret',
'created_at' => 1531054333,
],
'webhook-without-secret' => [
'id' => 2,
'url' => 'http://localhost:81/webhooks/ely',
'secret' => null,
'created_at' => 1531054837,
],
'webhook-without-events' => [
'id' => 3,
'url' => 'http://localhost:82/webhooks/ely',
'secret' => null,
'created_at' => 1531054990,
],
];

View File

@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace common\tests\helpers;
use phpmock\mockery\PHPMockery;
use ReflectionClass;
class Mock {
/**
* @param string $className
* @param string $function
*
* @return \Mockery\Expectation
*/
public static function func(string $className, string $function) {
return PHPMockery::mock(self::getClassNamespace($className), $function);
}
private static function getClassNamespace(string $className): string {
return (new ReflectionClass($className))->getNamespaceName();
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* @var $faker \Faker\Generator
* @var $index integer
*/
$security = Yii::$app->getSecurity();
return [
'uuid' => $faker->uuid,
'username' => $faker->userName,
'email' => $faker->email,
'password_hash' => $security->generatePasswordHash('password_' . $index),
'password_hash_strategy' => \common\models\Account::PASS_HASH_STRATEGY_YII2,
'lang' => 'en',
'auth_key' => $security->generateRandomString(),
'status' => \common\models\Account::STATUS_ACTIVE,
'created_at' => time(),
'updated_at' => time(),
];

View File

@@ -0,0 +1,9 @@
suite_namespace: common\tests\unit
actor: UnitTester
modules:
enabled:
- Yii2:
part: [orm, email, fixtures]
configFile: tests/config/unit.php
- common\tests\_support\queue\CodeceptionQueueHelper
- common\tests\_support\Mockery

View File

@@ -0,0 +1,29 @@
<?php
namespace common\tests\unit;
use Mockery;
class TestCase extends \Codeception\Test\Unit {
/**
* @var \common\tests\UnitTester
*/
protected $tester;
protected function tearDown() {
parent::tearDown();
Mockery::close();
}
/**
* Список фикстур, что будут загружены перед тестом, но после зачистки базы данных
*
* @url http://codeception.com/docs/modules/Yii2#fixtures
*
* @return array
*/
public function _fixtures() {
return [];
}
}

View File

@@ -0,0 +1,2 @@
<?php
// Here you can initialize variables that will for your tests

View File

@@ -0,0 +1,75 @@
<?php
namespace common\tests\unit\behaviors;
use Codeception\Specify;
use common\behaviors\DataBehavior;
use common\tests\_support\ProtectedCaller;
use common\tests\unit\TestCase;
use yii\base\ErrorException;
use yii\base\Model;
class DataBehaviorTest extends TestCase {
use Specify;
use ProtectedCaller;
public function testSetKey() {
$model = $this->createModel();
/** @var DataBehavior $behavior */
$behavior = $model->behaviors['dataBehavior'];
$this->callProtected($behavior, 'setKey', 'my-key', 'my-value');
$this->assertEquals(serialize(['my-key' => 'my-value']), $model->_data);
}
public function testGetKey() {
$model = $this->createModel();
$model->_data = serialize(['some-key' => 'some-value']);
/** @var DataBehavior $behavior */
$behavior = $model->behaviors['dataBehavior'];
$this->assertEquals('some-value', $this->callProtected($behavior, 'getKey', 'some-key'));
}
public function testGetData() {
$this->specify('getting value from null field should return empty array', function() {
$model = $this->createModel();
/** @var DataBehavior $behavior */
$behavior = $model->behaviors['dataBehavior'];
expect($this->callProtected($behavior, 'getData'))->equals([]);
});
$this->specify('getting value from serialized data field should return encoded value', function() {
$model = $this->createModel();
$data = ['foo' => 'bar'];
$model->_data = serialize($data);
/** @var DataBehavior $behavior */
$behavior = $model->behaviors['dataBehavior'];
expect($this->callProtected($behavior, 'getData'))->equals($data);
});
$this->specify('getting value from invalid serialization string', function() {
$model = $this->createModel();
$model->_data = 'this is invalid serialization of string';
/** @var DataBehavior $behavior */
$behavior = $model->behaviors['dataBehavior'];
$this->expectException(ErrorException::class);
$this->callProtected($behavior, 'getData');
});
}
/**
* @return Model
*/
private function createModel() {
return new class extends Model {
public $_data;
public function behaviors() {
return [
'dataBehavior' => [
'class' => DataBehavior::class,
],
];
}
};
}
}

View File

@@ -0,0 +1,109 @@
<?php
namespace common\tests\unit\behaviors;
use Codeception\Specify;
use common\behaviors\EmailActivationExpirationBehavior;
use common\tests\_support\ProtectedCaller;
use common\tests\unit\TestCase;
use yii\base\Model;
class EmailActivationExpirationBehaviorTest extends TestCase {
use Specify;
use ProtectedCaller;
public function testCalculateTime() {
$behavior = $this->createBehavior();
$time = time();
$behavior->owner->created_at = $time;
$this->assertEquals($time + 10, $this->callProtected($behavior, 'calculateTime', 10));
}
public function testCompareTime() {
$this->specify('expect false, if passed value is less then 0', function() {
$behavior = $this->createBehavior();
expect($this->callProtected($behavior, 'compareTime', -1))->false();
});
$this->specify('expect true, if passed value is equals 0', function() {
$behavior = $this->createBehavior();
expect($this->callProtected($behavior, 'compareTime', 0))->true();
});
$this->specify('expect true, if passed value is more than 0 and current time is greater then calculated', function() {
$behavior = $this->createBehavior();
$behavior->owner->created_at = time() - 10;
expect($this->callProtected($behavior, 'compareTime', 5))->true();
});
$this->specify('expect false, if passed value is more than 0 and current time is less then calculated', function() {
$behavior = $this->createBehavior();
$behavior->owner->created_at = time() - 2;
expect($this->callProtected($behavior, 'compareTime', 7))->false();
});
}
public function testCanRepeat() {
$this->specify('we can repeat, if created_at + repeatTimeout is greater, then current time', function() {
$behavior = $this->createBehavior();
$behavior->repeatTimeout = 30;
$behavior->owner->created_at = time() - 60;
expect($behavior->canRepeat())->true();
});
$this->specify('we cannot repeat, if created_at + repeatTimeout is less, then current time', function() {
$behavior = $this->createBehavior();
$behavior->repeatTimeout = 60;
$behavior->owner->created_at = time() - 30;
expect($behavior->canRepeat())->false();
});
}
public function testIsExpired() {
$this->specify('key is not expired, if created_at + expirationTimeout is greater, then current time', function() {
$behavior = $this->createBehavior();
$behavior->expirationTimeout = 30;
$behavior->owner->created_at = time() - 60;
expect($behavior->isExpired())->true();
});
$this->specify('key is not expired, if created_at + expirationTimeout is less, then current time', function() {
$behavior = $this->createBehavior();
$behavior->expirationTimeout = 60;
$behavior->owner->created_at = time() - 30;
expect($behavior->isExpired())->false();
});
}
public function testCanRepeatIn() {
$this->specify('get expected timestamp for repeat time moment', function() {
$behavior = $this->createBehavior();
$behavior->repeatTimeout = 30;
$behavior->owner->created_at = time() - 60;
expect($behavior->canRepeatIn())->equals($behavior->owner->created_at + $behavior->repeatTimeout);
});
}
public function testExpireIn() {
$this->specify('get expected timestamp for key expire moment', function() {
$behavior = $this->createBehavior();
$behavior->expirationTimeout = 30;
$behavior->owner->created_at = time() - 60;
expect($behavior->expireIn())->equals($behavior->owner->created_at + $behavior->expirationTimeout);
});
}
/**
* @return EmailActivationExpirationBehavior
*/
private function createBehavior() {
$behavior = new EmailActivationExpirationBehavior();
/** @var Model $model */
$model = new class extends Model {
public $created_at;
};
$model->attachBehavior('email-activation-behavior', $behavior);
return $behavior;
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace common\tests\unit\behaviors;
use Codeception\Specify;
use common\behaviors\PrimaryKeyValueBehavior;
use common\tests\unit\TestCase;
use yii\db\ActiveRecord;
class PrimaryKeyValueBehaviorTest extends TestCase {
use Specify;
public function testRefreshPrimaryKeyValue() {
$this->specify('method should generate value for primary key field on call', function() {
$model = new DummyModel();
/** @var PrimaryKeyValueBehavior|\PHPUnit_Framework_MockObject_MockObject $behavior */
$behavior = $this->getMockBuilder(PrimaryKeyValueBehavior::class)
->setMethods(['isValueExists'])
->setConstructorArgs([[
'value' => function() {
return 'mock';
},
]])
->getMock();
$behavior->expects($this->once())
->method('isValueExists')
->will($this->returnValue(false));
$model->attachBehavior('primary-key-value-behavior', $behavior);
$behavior->setPrimaryKeyValue();
expect($model->id)->equals('mock');
});
$this->specify('method should repeat value generation if generated value duplicate with exists', function() {
$model = new DummyModel();
/** @var PrimaryKeyValueBehavior|\PHPUnit_Framework_MockObject_MockObject $behavior */
$behavior = $this->getMockBuilder(PrimaryKeyValueBehavior::class)
->setMethods(['isValueExists', 'generateValue'])
->setConstructorArgs([[
'value' => function() {
return 'this was mocked, but let be passed';
},
]])
->getMock();
$behavior->expects($this->exactly(3))
->method('generateValue')
->will($this->onConsecutiveCalls('1', '2', '3'));
$behavior->expects($this->exactly(3))
->method('isValueExists')
->will($this->onConsecutiveCalls(true, true, false));
$model->attachBehavior('primary-key-value-behavior', $behavior);
$behavior->setPrimaryKeyValue();
expect($model->id)->equals('3');
});
}
}
class DummyModel extends ActiveRecord {
public $id;
public static function primaryKey() {
return ['id'];
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace common\tests\unit\components\Mojang;
use common\components\Mojang\Api;
use common\components\Mojang\response\UsernameToUUIDResponse;
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use common\tests\unit\TestCase;
use Yii;
class ApiTest extends TestCase {
/**
* @var MockHandler
*/
private $handler;
public function _before() {
parent::_before();
$this->handler = new MockHandler();
$handler = HandlerStack::create($this->handler);
Yii::$app->set('guzzle', new GuzzleClient([
'handler' => $handler,
]));
}
public function testUsernameToUUID() {
$this->handler->append(new Response(200, [], '{"id": "7125ba8b1c864508b92bb5c042ccfe2b","name": "KrisJelbring"}'));
$response = (new Api())->usernameToUUID('KrisJelbring');
$this->assertInstanceOf(UsernameToUUIDResponse::class, $response);
$this->assertEquals('7125ba8b1c864508b92bb5c042ccfe2b', $response->id);
$this->assertEquals('KrisJelbring', $response->name);
}
/**
* @expectedException \common\components\Mojang\exceptions\NoContentException
*/
public function testUsernameToUUIDNoContent() {
$this->handler->append(new Response(204));
(new Api())->usernameToUUID('some-non-exists-user');
}
/**
* @expectedException \GuzzleHttp\Exception\RequestException
*/
public function testUsernameToUUID404() {
$this->handler->append(new Response(404, [], '{"error":"Not Found","errorMessage":"The server has not found anything matching the request URI"}'));
(new Api())->usernameToUUID('#hashedNickname');
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace common\tests\unit\db\mysql;
use common\db\mysql\QueryBuilder;
use common\tests\unit\TestCase;
use Yii;
class QueryBuilderTest extends TestCase {
public function testBuildOrderByField() {
$queryBuilder = new QueryBuilder(Yii::$app->db);
$result = $queryBuilder->buildOrderBy(['dummy' => ['first', 'second']]);
$this->assertEquals("ORDER BY FIELD(`dummy`,'first','second')", $result);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace common\tests\unit\emails;
use common\emails\EmailHelper;
use common\tests\unit\TestCase;
class EmailHelperTest extends TestCase {
public function testBuildTo() {
$this->assertSame(['mock@ely.by' => 'username'], EmailHelper::buildTo('username', 'mock@ely.by'));
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace common\tests\unit\emails;
use common\emails\Template;
use common\tests\_support\ProtectedCaller;
use common\tests\unit\TestCase;
use Yii;
use yii\mail\MailerInterface;
use yii\mail\MessageInterface;
class TemplateTest extends TestCase {
use ProtectedCaller;
public function testConstructor() {
/** @var Template|\Mockery\MockInterface $template */
$template = mock(Template::class, ['find-me'])->makePartial();
$this->assertEquals('find-me', $template->getTo());
$this->assertInstanceOf(MailerInterface::class, $template->getMailer());
}
public function testGetFrom() {
Yii::$app->params['fromEmail'] = 'find-me';
/** @var Template|\Mockery\MockInterface $template */
$template = mock(Template::class)->makePartial();
$this->assertEquals(['find-me' => 'Ely.by Accounts'], $template->getFrom());
}
public function testGetParams() {
/** @var Template|\Mockery\MockInterface $template */
$template = mock(Template::class)->makePartial();
$this->assertEquals([], $template->getParams());
}
public function testCreateMessage() {
Yii::$app->params['fromEmail'] = 'from@ely.by';
/** @var Template|\Mockery\MockInterface $template */
$template = mock(Template::class, [['to@ely.by' => 'To']])->makePartial();
$template->shouldReceive('getSubject')->andReturn('mock-subject');
/** @var MessageInterface $message */
$message = $this->callProtected($template, 'createMessage');
$this->assertInstanceOf(MessageInterface::class, $message);
$this->assertEquals(['to@ely.by' => 'To'], $message->getTo());
$this->assertEquals(['from@ely.by' => 'Ely.by Accounts'], $message->getFrom());
$this->assertEquals('mock-subject', $message->getSubject());
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace common\tests\unit\emails;
use common\components\EmailRenderer;
use common\emails\TemplateWithRenderer;
use Ely\Email\TemplateBuilder;
use common\tests\_support\ProtectedCaller;
use common\tests\unit\TestCase;
use yii\mail\MailerInterface;
use yii\mail\MessageInterface;
class TemplateWithRendererTest extends TestCase {
use ProtectedCaller;
public function testConstructor() {
/** @var TemplateWithRenderer|\Mockery\MockInterface $template */
$template = mock(TemplateWithRenderer::class, ['mock-to', 'mock-locale'])->makePartial();
$this->assertEquals('mock-to', $template->getTo());
$this->assertEquals('mock-locale', $template->getLocale());
$this->assertInstanceOf(MailerInterface::class, $template->getMailer());
$this->assertInstanceOf(EmailRenderer::class, $template->getEmailRenderer());
}
public function testCreateMessage() {
/** @var TemplateBuilder|\Mockery\MockInterface $templateBuilder */
$templateBuilder = mock(TemplateBuilder::class)->makePartial();
$templateBuilder->shouldReceive('render')->andReturn('mock-html');
/** @var EmailRenderer|\Mockery\MockInterface $renderer */
$renderer = mock(EmailRenderer::class)->makePartial();
$renderer->shouldReceive('getTemplate')->with('mock-template')->andReturn($templateBuilder);
/** @var TemplateWithRenderer|\Mockery\MockInterface $template */
$template = mock(TemplateWithRenderer::class, [['to@ely.by' => 'To'], 'mock-locale']);
$template->makePartial();
$template->shouldReceive('getEmailRenderer')->andReturn($renderer);
$template->shouldReceive('getFrom')->andReturn(['from@ely.by' => 'From']);
$template->shouldReceive('getSubject')->andReturn('mock-subject');
$template->shouldReceive('getTemplateName')->andReturn('mock-template');
/** @var \yii\swiftmailer\Message $message */
$message = $this->callProtected($template, 'createMessage');
$this->assertInstanceOf(MessageInterface::class, $message);
$this->assertEquals(['to@ely.by' => 'To'], $message->getTo());
$this->assertEquals(['from@ely.by' => 'From'], $message->getFrom());
$this->assertEquals('mock-subject', $message->getSubject());
$this->assertEquals('mock-html', $message->getSwiftMessage()->getBody());
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace common\tests\unit\helpers;
use common\helpers\StringHelper;
use common\tests\unit\TestCase;
class StringHelperTest extends TestCase {
public function testGetEmailMask() {
$this->assertEquals('**@ely.by', StringHelper::getEmailMask('e@ely.by'));
$this->assertEquals('e**@ely.by', StringHelper::getEmailMask('es@ely.by'));
$this->assertEquals('e**i@ely.by', StringHelper::getEmailMask('eri@ely.by'));
$this->assertEquals('er**ch@ely.by', StringHelper::getEmailMask('erickskrauch@ely.by'));
$this->assertEquals('эр**уч@елу.бел', StringHelper::getEmailMask('эрикскрауч@елу.бел'));
}
public function testIsUuid() {
$this->assertTrue(StringHelper::isUuid('a80b4487-a5c6-45a5-9829-373b4a494135'));
$this->assertTrue(StringHelper::isUuid('a80b4487a5c645a59829373b4a494135'));
$this->assertFalse(StringHelper::isUuid('12345678'));
}
/**
* @dataProvider trimProvider()
*/
public function testTrim($expected, $string) {
$result = StringHelper::trim($string);
$this->assertEquals($expected, $result);
}
/**
* http://jkorpela.fi/chars/spaces.html
* http://www.alanwood.net/unicode/general_punctuation.html
*
* @return array
*/
public function trimProvider() {
return [
['foo bar', ' foo bar '], // Simple spaces
['foo bar', ' foo bar'], // Only left side space
['foo bar', 'foo bar '], // Only right side space
['foo bar', "\n\t foo bar \n\t"], // New line, tab character and simple space
['fòô bàř', ' fòô bàř '], // UTF-8 text
['fòô bàř', ' fòô bàř'], // Only left side space width UTF-8 text
['fòô bàř', 'fòô bàř '], // Only right side space width UTF-8 text
['fòô bàř', "\n\t fòô bàř \n\t"], // New line, tab character and simple space width UTF-8 string
['fòô', "\u{00a0}fòô\u{00a0}"], // No-break space (U+00A0)
['fòô', "\u{1680}fòô\u{1680}"], // Ogham space mark (U+1680)
['fòô', "\u{180e}fòô\u{180e}"], // Mongolian vowel separator (U+180E)
['fòô', "\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}fòô"], // Spaces U+2000 to U+2007
['fòô', "\u{2008}\u{2009}\u{200a}\u{200b}\u{200c}\u{200d}\u{200e}\u{200f}fòô"], // Spaces U+2008 to U+200F
['fòô', "\u{2028}\u{2029}\u{202a}\u{202b}\u{202c}\u{202d}\u{202e}\u{202f}fòô"], // Spaces U+2028 to U+202F
['fòô', "\u{2060}\u{2061}\u{2062}\u{2063}\u{2064}\u{2065}\u{2066}\u{2067}fòô"], // Spaces U+2060 to U+2067
['fòô', "\u{2068}\u{2069}\u{206a}\u{206b}\u{206c}\u{206d}\u{206e}\u{206f}fòô"], // Spaces U+2068 to U+206F
['fòô', "\u{205f}fòô\u{205f}"], // Medium mathematical space (U+205F)
['fòô', "\u{3000}fòô\u{3000}"], // Ideographic space (U+3000)
['fòô', "\u{feff}fòô\u{feff}"], // Zero width no-break space (U+FEFF)
];
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace common\tests\unit\models;
use common\models\AccountSession;
use common\tests\unit\TestCase;
class AccountSessionTest extends TestCase {
public function testGenerateRefreshToken() {
$model = new AccountSession();
$model->generateRefreshToken();
$this->assertNotNull($model->refresh_token, 'method call will set refresh_token value');
}
public function testSetIp() {
$model = new AccountSession();
$model->setIp('127.0.0.1');
$this->assertEquals(2130706433, $model->last_used_ip, 'method should convert passed ip string to long');
}
public function testGetReadableIp() {
$model = new AccountSession();
$model->last_used_ip = 2130706433;
$this->assertEquals('127.0.0.1', $model->getReadableIp(), 'method should convert stored long into readable ip');
}
}

View File

@@ -0,0 +1,161 @@
<?php
declare(strict_types=1);
namespace common\tests\unit\models;
use Codeception\Specify;
use common\components\UserPass;
use common\models\Account;
use common\tasks\CreateWebHooksDeliveries;
use common\tests\fixtures\MojangUsernameFixture;
use common\tests\unit\TestCase;
use Yii;
use const common\LATEST_RULES_VERSION;
/**
* @covers \common\models\Account
*/
class AccountTest extends TestCase {
use Specify;
public function testSetPassword() {
$model = new Account();
$model->setPassword('12345678');
$this->assertNotEmpty($model->password_hash, 'hash should be set');
$this->assertTrue($model->validatePassword('12345678'), 'validation should be passed');
$this->assertEquals(Account::PASS_HASH_STRATEGY_YII2, $model->password_hash_strategy, 'latest password hash should be used');
}
public function testValidatePassword() {
$this->specify('old Ely password should work', function() {
$model = new Account([
'email' => 'erick@skrauch.net',
'password_hash' => UserPass::make('erick@skrauch.net', '12345678'),
]);
expect('valid password should pass', $model->validatePassword('12345678', Account::PASS_HASH_STRATEGY_OLD_ELY))->true();
expect('invalid password should fail', $model->validatePassword('87654321', Account::PASS_HASH_STRATEGY_OLD_ELY))->false();
});
$this->specify('modern hash algorithm should work', function() {
$model = new Account([
'password_hash' => Yii::$app->security->generatePasswordHash('12345678'),
]);
expect('valid password should pass', $model->validatePassword('12345678', Account::PASS_HASH_STRATEGY_YII2))->true();
expect('invalid password should fail', $model->validatePassword('87654321', Account::PASS_HASH_STRATEGY_YII2))->false();
});
$this->specify('if second argument is not pass model value should be used', function() {
$model = new Account([
'email' => 'erick@skrauch.net',
'password_hash_strategy' => Account::PASS_HASH_STRATEGY_OLD_ELY,
'password_hash' => UserPass::make('erick@skrauch.net', '12345678'),
]);
expect('valid password should pass', $model->validatePassword('12345678'))->true();
expect('invalid password should fail', $model->validatePassword('87654321'))->false();
$model = new Account([
'password_hash_strategy' => Account::PASS_HASH_STRATEGY_YII2,
'password_hash' => Yii::$app->security->generatePasswordHash('12345678'),
]);
expect('valid password should pass', $model->validatePassword('12345678'))->true();
expect('invalid password should fail', $model->validatePassword('87654321'))->false();
});
}
public function testHasMojangUsernameCollision() {
$this->tester->haveFixtures([
'mojangUsernames' => MojangUsernameFixture::class,
]);
$this->specify('Expect true if collision with current username', function() {
$model = new Account();
$model->username = 'ErickSkrauch';
expect($model->hasMojangUsernameCollision())->true();
});
$this->specify('Expect false if some rare username without any collision on Mojang', function() {
$model = new Account();
$model->username = 'rare-username';
expect($model->hasMojangUsernameCollision())->false();
});
}
public function testGetProfileLink() {
$model = new Account();
$model->id = '123';
$this->assertEquals('http://ely.by/u123', $model->getProfileLink());
}
public function testIsAgreedWithActualRules() {
$this->specify('get false, if rules field set in null', function() {
$model = new Account();
expect($model->isAgreedWithActualRules())->false();
});
$this->specify('get false, if rules field have version less, then actual', function() {
$model = new Account();
$model->rules_agreement_version = 0;
expect($model->isAgreedWithActualRules())->false();
});
$this->specify('get true, if rules field have equals rules version', function() {
$model = new Account();
$model->rules_agreement_version = LATEST_RULES_VERSION;
expect($model->isAgreedWithActualRules())->true();
});
}
public function testSetRegistrationIp() {
$account = new Account();
$account->setRegistrationIp('42.72.205.204');
$this->assertEquals('42.72.205.204', inet_ntop($account->registration_ip));
$account->setRegistrationIp('2001:1620:28:1:b6f:8bca:93:a116');
$this->assertEquals('2001:1620:28:1:b6f:8bca:93:a116', inet_ntop($account->registration_ip));
$account->setRegistrationIp(null);
$this->assertNull($account->registration_ip);
}
public function testGetRegistrationIp() {
$account = new Account();
$account->setRegistrationIp('42.72.205.204');
$this->assertEquals('42.72.205.204', $account->getRegistrationIp());
$account->setRegistrationIp('2001:1620:28:1:b6f:8bca:93:a116');
$this->assertEquals('2001:1620:28:1:b6f:8bca:93:a116', $account->getRegistrationIp());
$account->setRegistrationIp(null);
$this->assertNull($account->getRegistrationIp());
}
public function testAfterSaveInsertEvent() {
$account = new Account();
$account->afterSave(true, [
'username' => 'old-username',
]);
$this->assertNull($this->tester->grabLastQueuedJob());
}
public function testAfterSaveNotMeaningfulAttributes() {
$account = new Account();
$account->afterSave(false, [
'updatedAt' => time(),
]);
$this->assertNull($this->tester->grabLastQueuedJob());
}
public function testAfterSavePushEvent() {
$changedAttributes = [
'username' => 'old-username',
'email' => 'old-email@ely.by',
'uuid' => 'c3cc0121-fa87-4818-9c0e-4acb7f9a28c5',
'status' => 10,
'lang' => 'en',
];
$account = new Account();
$account->afterSave(false, $changedAttributes);
/** @var CreateWebHooksDeliveries $job */
$job = $this->tester->grabLastQueuedJob();
$this->assertInstanceOf(CreateWebHooksDeliveries::class, $job);
$this->assertSame($job->payloads['changedAttributes'], $changedAttributes);
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace common\tests\unit\models;
use common\models\confirmations;
use common\models\EmailActivation;
use common\tests\fixtures\EmailActivationFixture;
use common\tests\unit\TestCase;
class EmailActivationTest extends TestCase {
public function _fixtures() {
return [
'emailActivations' => EmailActivationFixture::class,
];
}
public function testInstantiate() {
$this->assertInstanceOf(confirmations\RegistrationConfirmation::class, EmailActivation::findOne([
'type' => EmailActivation::TYPE_REGISTRATION_EMAIL_CONFIRMATION,
]));
$this->assertInstanceOf(confirmations\ForgotPassword::class, EmailActivation::findOne([
'type' => EmailActivation::TYPE_FORGOT_PASSWORD_KEY,
]));
$this->assertInstanceOf(confirmations\CurrentEmailConfirmation::class, EmailActivation::findOne([
'type' => EmailActivation::TYPE_CURRENT_EMAIL_CONFIRMATION,
]));
$this->assertInstanceOf(confirmations\NewEmailConfirmation::class, EmailActivation::findOne([
'type' => EmailActivation::TYPE_NEW_EMAIL_CONFIRMATION,
]));
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace common\tests\unit\models;
use common\models\OauthClient;
use common\tests\fixtures\OauthClientFixture;
use common\tests\unit\TestCase;
class OauthClientQueryTest extends TestCase {
public function _fixtures() {
return [
'oauthClients' => OauthClientFixture::class,
];
}
public function testDefaultHideDeletedEntries() {
/** @var OauthClient[] $clients */
$clients = OauthClient::find()->all();
$this->assertEmpty(array_filter($clients, function(OauthClient $client) {
return (bool)$client->is_deleted === true;
}));
$this->assertNull(OauthClient::findOne('deleted-oauth-client'));
}
public function testAllowFindDeletedEntries() {
/** @var OauthClient[] $clients */
$clients = OauthClient::find()->includeDeleted()->all();
$this->assertNotEmpty(array_filter($clients, function(OauthClient $client) {
return (bool)$client->is_deleted === true;
}));
$client = OauthClient::find()
->includeDeleted()
->andWhere(['id' => 'deleted-oauth-client'])
->one();
$this->assertInstanceOf(OauthClient::class, $client);
$deletedClients = OauthClient::find()->onlyDeleted()->all();
$this->assertEmpty(array_filter($deletedClients, function(OauthClient $client) {
return (bool)$client->is_deleted === false;
}));
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace common\tests\unit\rbac\rules;
use api\components\User\Component;
use api\components\User\IdentityInterface;
use common\models\Account;
use common\rbac\rules\AccountOwner;
use common\tests\unit\TestCase;
use Yii;
use yii\rbac\Item;
use const common\LATEST_RULES_VERSION;
class AccountOwnerTest extends TestCase {
public function testIdentityIsNull() {
$component = mock(Component::class . '[findIdentityByAccessToken]', [['secret' => 'secret']]);
$component->shouldDeferMissing();
$component->shouldReceive('findIdentityByAccessToken')->andReturn(null);
Yii::$app->set('user', $component);
$this->assertFalse((new AccountOwner())->execute('some token', new Item(), ['accountId' => 123]));
}
public function testExecute() {
$rule = new AccountOwner();
$item = new Item();
$account = new Account();
$account->id = 1;
$account->status = Account::STATUS_ACTIVE;
$account->rules_agreement_version = LATEST_RULES_VERSION;
$identity = mock(IdentityInterface::class);
$identity->shouldReceive('getAccount')->andReturn($account);
$component = mock(Component::class . '[findIdentityByAccessToken]', [['secret' => 'secret']]);
$component->shouldDeferMissing();
$component->shouldReceive('findIdentityByAccessToken')->withArgs(['token'])->andReturn($identity);
Yii::$app->set('user', $component);
$this->assertFalse($rule->execute('token', $item, []));
$this->assertFalse($rule->execute('token', $item, ['accountId' => 2]));
$this->assertFalse($rule->execute('token', $item, ['accountId' => '2']));
$this->assertTrue($rule->execute('token', $item, ['accountId' => 1]));
$this->assertTrue($rule->execute('token', $item, ['accountId' => '1']));
$account->rules_agreement_version = null;
$this->assertFalse($rule->execute('token', $item, ['accountId' => 1]));
$this->assertTrue($rule->execute('token', $item, ['accountId' => 1, 'optionalRules' => true]));
$account->rules_agreement_version = LATEST_RULES_VERSION;
$account->status = Account::STATUS_BANNED;
$this->assertFalse($rule->execute('token', $item, ['accountId' => 1]));
$this->assertFalse($rule->execute('token', $item, ['accountId' => 1, 'optionalRules' => true]));
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace common\tests\unit\rbac\rules;
use api\components\User\Component;
use api\components\User\IdentityInterface;
use common\models\Account;
use common\rbac\Permissions as P;
use common\rbac\rules\OauthClientOwner;
use common\tests\fixtures\OauthClientFixture;
use common\tests\unit\TestCase;
use Yii;
use yii\rbac\Item;
use const common\LATEST_RULES_VERSION;
class OauthClientOwnerTest extends TestCase {
public function _fixtures() {
return [
'oauthClients' => OauthClientFixture::class,
];
}
public function testExecute() {
$rule = new OauthClientOwner();
$item = new Item();
$account = new Account();
$account->id = 1;
$account->status = Account::STATUS_ACTIVE;
$account->rules_agreement_version = LATEST_RULES_VERSION;
/** @var IdentityInterface|\Mockery\MockInterface $identity */
$identity = mock(IdentityInterface::class);
$identity->shouldReceive('getAccount')->andReturn($account);
/** @var Component|\Mockery\MockInterface $component */
$component = mock(Component::class . '[findIdentityByAccessToken]', [['secret' => 'secret']]);
$component->shouldDeferMissing();
$component->shouldReceive('findIdentityByAccessToken')->withArgs(['token'])->andReturn($identity);
Yii::$app->set('user', $component);
$this->assertFalse($rule->execute('token', $item, []));
$this->assertTrue($rule->execute('token', $item, ['clientId' => 'admin-oauth-client']));
$this->assertTrue($rule->execute('token', $item, ['clientId' => 'not-exists-client']));
$account->id = 2;
$this->assertFalse($rule->execute('token', $item, ['clientId' => 'admin-oauth-client']));
$item->name = P::VIEW_OWN_OAUTH_CLIENTS;
$this->assertTrue($rule->execute('token', $item, ['accountId' => 2]));
$this->assertFalse($rule->execute('token', $item, ['accountId' => 1]));
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace common\tests\unit\tasks;
use common\models\Account;
use common\tasks\ClearAccountSessions;
use common\tests\fixtures;
use common\tests\unit\TestCase;
use yii\queue\Queue;
/**
* @covers \common\tasks\ClearAccountSessions
*/
class ClearAccountSessionsTest extends TestCase {
public function _fixtures() {
return [
'accounts' => fixtures\AccountFixture::class,
'oauthSessions' => fixtures\OauthSessionFixture::class,
'minecraftAccessKeys' => fixtures\MinecraftAccessKeyFixture::class,
'authSessions' => fixtures\AccountSessionFixture::class,
];
}
public function testCreateFromAccount() {
$account = new Account();
$account->id = 123;
$task = ClearAccountSessions::createFromAccount($account);
$this->assertSame(123, $task->accountId);
}
public function testExecute() {
/** @var \common\models\Account $bannedAccount */
$bannedAccount = $this->tester->grabFixture('accounts', 'banned-account');
$task = new ClearAccountSessions();
$task->accountId = $bannedAccount->id;
$task->execute(mock(Queue::class));
$this->assertEmpty($bannedAccount->sessions);
$this->assertEmpty($bannedAccount->minecraftAccessKeys);
$this->assertEmpty($bannedAccount->oauthSessions);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace common\tests\unit\tasks;
use common\models\OauthClient;
use common\models\OauthSession;
use common\tasks\ClearOauthSessions;
use common\tests\fixtures;
use common\tests\unit\TestCase;
use yii\queue\Queue;
class ClearOauthSessionsTest extends TestCase {
public function _fixtures() {
return [
'oauthClients' => fixtures\OauthClientFixture::class,
'oauthSessions' => fixtures\OauthSessionFixture::class,
];
}
public function testCreateFromClient() {
$client = new OauthClient();
$client->id = 'mocked-id';
$result = ClearOauthSessions::createFromOauthClient($client);
$this->assertInstanceOf(ClearOauthSessions::class, $result);
$this->assertSame('mocked-id', $result->clientId);
$this->assertNull($result->notSince);
$result = ClearOauthSessions::createFromOauthClient($client, time());
$this->assertInstanceOf(ClearOauthSessions::class, $result);
$this->assertSame('mocked-id', $result->clientId);
$this->assertEquals(time(), $result->notSince, '', 1);
}
public function testExecute() {
$task = new ClearOauthSessions();
$task->clientId = 'deleted-oauth-client-with-sessions';
$task->notSince = 1519510065;
$task->execute(mock(Queue::class));
$this->assertFalse(OauthSession::find()->andWhere(['id' => 3])->exists());
$this->assertTrue(OauthSession::find()->andWhere(['id' => 4])->exists());
$task = new ClearOauthSessions();
$task->clientId = 'deleted-oauth-client-with-sessions';
$task->execute(mock(Queue::class));
$this->assertFalse(OauthSession::find()->andWhere(['id' => 4])->exists());
$task = new ClearOauthSessions();
$task->clientId = 'some-not-exists-client-id';
$task->execute(mock(Queue::class));
}
}

View File

@@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace common\tests\unit\tasks;
use common\models\Account;
use common\tasks\CreateWebHooksDeliveries;
use common\tasks\DeliveryWebHook;
use common\tests\fixtures;
use common\tests\unit\TestCase;
use yii\queue\Queue;
/**
* @covers \common\tasks\CreateWebHooksDeliveries
*/
class CreateWebHooksDeliveriesTest extends TestCase {
public function _fixtures(): array {
return [
'webhooks' => fixtures\WebHooksFixture::class,
'webhooksEvents' => fixtures\WebHooksEventsFixture::class,
];
}
public function testCreateAccountEdit() {
$account = new Account();
$account->id = 123;
$account->username = 'mock-username';
$account->uuid = 'afc8dc7a-4bbf-4d3a-8699-68890088cf84';
$account->email = 'mock@ely.by';
$account->lang = 'en';
$account->status = Account::STATUS_ACTIVE;
$account->created_at = 1531008814;
$changedAttributes = [
'username' => 'old-username',
'uuid' => 'e05d33e9-ff91-4d26-9f5c-8250f802a87a',
'email' => 'old-email@ely.by',
'status' => 0,
];
$result = CreateWebHooksDeliveries::createAccountEdit($account, $changedAttributes);
$this->assertInstanceOf(CreateWebHooksDeliveries::class, $result);
$this->assertSame('account.edit', $result->type);
$this->assertArraySubset([
'id' => 123,
'uuid' => 'afc8dc7a-4bbf-4d3a-8699-68890088cf84',
'username' => 'mock-username',
'email' => 'mock@ely.by',
'lang' => 'en',
'isActive' => true,
'registered' => '2018-07-08T00:13:34+00:00',
'changedAttributes' => $changedAttributes,
], $result->payloads);
}
public function testExecute() {
$task = new CreateWebHooksDeliveries();
$task->type = 'account.edit';
$task->payloads = [
'id' => 123,
'uuid' => 'afc8dc7a-4bbf-4d3a-8699-68890088cf84',
'username' => 'mock-username',
'email' => 'mock@ely.by',
'lang' => 'en',
'isActive' => true,
'registered' => '2018-07-08T00:13:34+00:00',
'changedAttributes' => [
'username' => 'old-username',
'uuid' => 'e05d33e9-ff91-4d26-9f5c-8250f802a87a',
'email' => 'old-email@ely.by',
'status' => 0,
],
];
$task->execute(mock(Queue::class));
/** @var DeliveryWebHook[] $tasks */
$tasks = $this->tester->grabQueueJobs();
$this->assertCount(2, $tasks);
$this->assertInstanceOf(DeliveryWebHook::class, $tasks[0]);
$this->assertSame($task->type, $tasks[0]->type);
$this->assertSame($task->payloads, $tasks[0]->payloads);
$this->assertSame('http://localhost:80/webhooks/ely', $tasks[0]->url);
$this->assertSame('my-secret', $tasks[0]->secret);
$this->assertInstanceOf(DeliveryWebHook::class, $tasks[1]);
$this->assertSame($task->type, $tasks[1]->type);
$this->assertSame($task->payloads, $tasks[1]->payloads);
$this->assertSame('http://localhost:81/webhooks/ely', $tasks[1]->url);
$this->assertNull($tasks[1]->secret);
}
}

View File

@@ -0,0 +1,133 @@
<?php
declare(strict_types=1);
namespace common\tests\unit\tasks;
use common\tasks\DeliveryWebHook;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\ServerException;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use common\tests\unit\TestCase;
use yii\queue\Queue;
/**
* @covers \common\tasks\DeliveryWebHook
*/
class DeliveryWebHookTest extends TestCase {
private $historyContainer = [];
/**
* @var Response|\GuzzleHttp\Exception\GuzzleException
*/
private $response;
public function testCanRetry() {
$task = new DeliveryWebHook();
$this->assertFalse($task->canRetry(1, new \Exception()));
$request = new Request('POST', 'http://localhost');
$this->assertTrue($task->canRetry(4, new ConnectException('', $request)));
$this->assertTrue($task->canRetry(4, new ServerException('', $request)));
$this->assertFalse($task->canRetry(5, new ConnectException('', $request)));
$this->assertFalse($task->canRetry(5, new ServerException('', $request)));
}
public function testExecuteSuccessDelivery() {
$this->response = new Response();
$task = $this->createMockedTask();
$task->type = 'account.edit';
$task->url = 'http://localhost:81/webhooks/ely';
$task->payloads = [
'key' => 'value',
'another' => 'value',
];
$task->execute(mock(Queue::class));
/** @var Request $request */
$request = $this->historyContainer[0]['request'];
$this->assertSame('http://localhost:81/webhooks/ely', (string)$request->getUri());
$this->assertStringStartsWith('Account-Ely-Hookshot/', $request->getHeaders()['User-Agent'][0]);
$this->assertSame('account.edit', $request->getHeaders()['X-Ely-Accounts-Event'][0]);
$this->assertSame('application/x-www-form-urlencoded', $request->getHeaders()['Content-Type'][0]);
$this->assertArrayNotHasKey('X-Hub-Signature', $request->getHeaders());
$this->assertEquals('key=value&another=value', (string)$request->getBody());
}
public function testExecuteSuccessDeliveryWithSignature() {
$this->response = new Response();
$task = $this->createMockedTask();
$task->type = 'account.edit';
$task->url = 'http://localhost:81/webhooks/ely';
$task->secret = 'secret';
$task->payloads = [
'key' => 'value',
'another' => 'value',
];
$task->execute(mock(Queue::class));
/** @var Request $request */
$request = $this->historyContainer[0]['request'];
$this->assertSame('http://localhost:81/webhooks/ely', (string)$request->getUri());
$this->assertStringStartsWith('Account-Ely-Hookshot/', $request->getHeaders()['User-Agent'][0]);
$this->assertSame('account.edit', $request->getHeaders()['X-Ely-Accounts-Event'][0]);
$this->assertSame('application/x-www-form-urlencoded', $request->getHeaders()['Content-Type'][0]);
$this->assertSame('sha1=3c0b1eef564b2d3a5e9c0f2a8302b1b42b3d4784', $request->getHeaders()['X-Hub-Signature'][0]);
$this->assertEquals('key=value&another=value', (string)$request->getBody());
}
public function testExecuteHandleClientException() {
$this->response = new Response(403);
$task = $this->createMockedTask();
$task->type = 'account.edit';
$task->url = 'http://localhost:81/webhooks/ely';
$task->secret = 'secret';
$task->payloads = [
'key' => 'value',
'another' => 'value',
];
$task->execute(mock(Queue::class));
}
/**
* @expectedException \GuzzleHttp\Exception\ServerException
*/
public function testExecuteUnhandledException() {
$this->response = new Response(502);
$task = $this->createMockedTask();
$task->type = 'account.edit';
$task->url = 'http://localhost:81/webhooks/ely';
$task->secret = 'secret';
$task->payloads = [
'key' => 'value',
'another' => 'value',
];
$task->execute(mock(Queue::class));
}
private function createMockedTask(): DeliveryWebHook {
$container = &$this->historyContainer;
$response = $this->response;
return new class($container, $response) extends DeliveryWebHook {
private $historyContainer;
private $response;
public function __construct(array &$historyContainer, $response) {
$this->historyContainer = &$historyContainer;
$this->response = $response;
}
protected function createStack(): HandlerStack {
$stack = parent::createStack();
$stack->setHandler(new MockHandler([$this->response]));
$stack->push(Middleware::history($this->historyContainer));
return $stack;
}
};
}
}

View File

@@ -0,0 +1,148 @@
<?php
declare(strict_types=1);
namespace common\tests\unit\tasks;
use common\components\Mojang\Api;
use common\components\Mojang\exceptions\NoContentException;
use common\components\Mojang\response\UsernameToUUIDResponse;
use common\models\Account;
use common\models\MojangUsername;
use common\tasks\PullMojangUsername;
use common\tests\fixtures\MojangUsernameFixture;
use common\tests\unit\TestCase;
use yii\queue\Queue;
/**
* @covers \common\tasks\PullMojangUsername
*/
class PullMojangUsernameTest extends TestCase {
private $expectedResponse;
/**
* @var PullMojangUsername
*/
private $task;
public function _fixtures() {
return [
'mojangUsernames' => MojangUsernameFixture::class,
];
}
public function _before() {
parent::_before();
/** @var PullMojangUsername|\PHPUnit_Framework_MockObject_MockObject $task */
$task = $this->getMockBuilder(PullMojangUsername::class)
->setMethods(['createMojangApi'])
->getMock();
/** @var Api|\PHPUnit_Framework_MockObject_MockObject $apiMock */
$apiMock = $this->getMockBuilder(Api::class)
->setMethods(['usernameToUUID'])
->getMock();
$apiMock
->expects($this->any())
->method('usernameToUUID')
->willReturnCallback(function() {
if ($this->expectedResponse === false) {
throw new NoContentException();
}
return $this->expectedResponse;
});
$task
->expects($this->any())
->method('createMojangApi')
->willReturn($apiMock);
$this->task = $task;
}
public function testCreateFromAccount() {
$account = new Account();
$account->username = 'find-me';
$result = PullMojangUsername::createFromAccount($account);
$this->assertSame('find-me', $result->username);
}
public function testExecuteUsernameExists() {
$expectedResponse = new UsernameToUUIDResponse();
$expectedResponse->id = '069a79f444e94726a5befca90e38aaf5';
$expectedResponse->name = 'Notch';
$this->expectedResponse = $expectedResponse;
/** @var \common\models\MojangUsername $mojangUsernameFixture */
$mojangUsernameFixture = $this->tester->grabFixture('mojangUsernames', 'Notch');
$this->task->username = 'Notch';
$this->task->execute(mock(Queue::class));
/** @var MojangUsername|null $mojangUsername */
$mojangUsername = MojangUsername::findOne('Notch');
$this->assertInstanceOf(MojangUsername::class, $mojangUsername);
$this->assertGreaterThan($mojangUsernameFixture->last_pulled_at, $mojangUsername->last_pulled_at);
$this->assertLessThanOrEqual(time(), $mojangUsername->last_pulled_at);
}
public function testExecuteChangedUsernameExists() {
$expectedResponse = new UsernameToUUIDResponse();
$expectedResponse->id = '069a79f444e94726a5befca90e38aaf5';
$expectedResponse->name = 'Notch';
$this->expectedResponse = $expectedResponse;
/** @var MojangUsername $mojangUsernameFixture */
$mojangUsernameFixture = $this->tester->grabFixture('mojangUsernames', 'Notch');
$this->task->username = 'Notch';
$this->task->execute(mock(Queue::class));
/** @var MojangUsername|null $mojangUsername */
$mojangUsername = MojangUsername::findOne('Notch');
$this->assertInstanceOf(MojangUsername::class, $mojangUsername);
$this->assertGreaterThan($mojangUsernameFixture->last_pulled_at, $mojangUsername->last_pulled_at);
$this->assertLessThanOrEqual(time(), $mojangUsername->last_pulled_at);
}
public function testExecuteChangedUsernameNotExists() {
$expectedResponse = new UsernameToUUIDResponse();
$expectedResponse->id = '607153852b8c4909811f507ed8ee737f';
$expectedResponse->name = 'Chest';
$this->expectedResponse = $expectedResponse;
$this->task->username = 'Chest';
$this->task->execute(mock(Queue::class));
/** @var MojangUsername|null $mojangUsername */
$mojangUsername = MojangUsername::findOne('Chest');
$this->assertInstanceOf(MojangUsername::class, $mojangUsername);
}
public function testExecuteRemoveIfExistsNoMore() {
$this->expectedResponse = false;
$username = $this->tester->grabFixture('mojangUsernames', 'not-exists')['username'];
$this->task->username = $username;
$this->task->execute(mock(Queue::class));
/** @var MojangUsername|null $mojangUsername */
$mojangUsername = MojangUsername::findOne($username);
$this->assertNull($mojangUsername);
}
public function testExecuteUuidUpdated() {
$expectedResponse = new UsernameToUUIDResponse();
$expectedResponse->id = 'f498513ce8c84773be26ecfc7ed5185d';
$expectedResponse->name = 'jeb';
$this->expectedResponse = $expectedResponse;
/** @var MojangUsername $mojangInfo */
$mojangInfo = $this->tester->grabFixture('mojangUsernames', 'uuid-changed');
$username = $mojangInfo['username'];
$this->task->username = $username;
$this->task->execute(mock(Queue::class));
/** @var MojangUsername|null $mojangUsername */
$mojangUsername = MojangUsername::findOne($username);
$this->assertInstanceOf(MojangUsername::class, $mojangUsername);
$this->assertNotEquals($mojangInfo->uuid, $mojangUsername->uuid);
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace common\tests\unit\tasks;
use common\models\Account;
use common\models\confirmations\CurrentEmailConfirmation;
use common\tasks\SendCurrentEmailConfirmation;
use common\tests\unit\TestCase;
use yii\queue\Queue;
class SendCurrentEmailConfirmationTest extends TestCase {
public function testCreateFromConfirmation() {
$account = new Account();
$account->username = 'mock-username';
$account->email = 'mock@ely.by';
$account->lang = 'id';
/** @var \Mockery\Mock|CurrentEmailConfirmation $confirmation */
$confirmation = mock(CurrentEmailConfirmation::class)->makePartial();
$confirmation->key = 'ABCDEFG';
$confirmation->shouldReceive('getAccount')->andReturn($account);
$result = SendCurrentEmailConfirmation::createFromConfirmation($confirmation);
$this->assertInstanceOf(SendCurrentEmailConfirmation::class, $result);
$this->assertSame('mock-username', $result->username);
$this->assertSame('mock@ely.by', $result->email);
$this->assertSame('ABCDEFG', $result->code);
}
public function testExecute() {
$task = new SendCurrentEmailConfirmation();
$task->username = 'mock-username';
$task->email = 'mock@ely.by';
$task->code = 'GFEDCBA';
$task->execute(mock(Queue::class));
$this->tester->canSeeEmailIsSent(1);
/** @var \yii\swiftmailer\Message $email */
$email = $this->tester->grabSentEmails()[0];
$this->assertSame(['mock@ely.by' => 'mock-username'], $email->getTo());
$this->assertSame('Ely.by Account change E-mail confirmation', $email->getSubject());
$children = $email->getSwiftMessage()->getChildren()[0];
$this->assertContains('GFEDCBA', $children->getBody());
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace common\tests\unit\tasks;
use common\models\Account;
use common\models\confirmations\NewEmailConfirmation;
use common\tasks\SendNewEmailConfirmation;
use common\tests\unit\TestCase;
use yii\queue\Queue;
class SendNewEmailConfirmationTest extends TestCase {
public function testCreateFromConfirmation() {
$account = new Account();
$account->username = 'mock-username';
$account->lang = 'id';
/** @var \Mockery\Mock|NewEmailConfirmation $confirmation */
$confirmation = mock(NewEmailConfirmation::class)->makePartial();
$confirmation->key = 'ABCDEFG';
$confirmation->shouldReceive('getAccount')->andReturn($account);
$confirmation->shouldReceive('getNewEmail')->andReturn('new-email@ely.by');
$result = SendNewEmailConfirmation::createFromConfirmation($confirmation);
$this->assertInstanceOf(SendNewEmailConfirmation::class, $result);
$this->assertSame('mock-username', $result->username);
$this->assertSame('new-email@ely.by', $result->email);
$this->assertSame('ABCDEFG', $result->code);
}
public function testExecute() {
$task = new SendNewEmailConfirmation();
$task->username = 'mock-username';
$task->email = 'mock@ely.by';
$task->code = 'GFEDCBA';
$task->execute(mock(Queue::class));
$this->tester->canSeeEmailIsSent(1);
/** @var \yii\swiftmailer\Message $email */
$email = $this->tester->grabSentEmails()[0];
$this->assertSame(['mock@ely.by' => 'mock-username'], $email->getTo());
$this->assertSame('Ely.by Account new E-mail confirmation', $email->getSubject());
$children = $email->getSwiftMessage()->getChildren()[0];
$this->assertContains('GFEDCBA', $children->getBody());
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace common\tests\unit\tasks;
use common\models\Account;
use common\models\confirmations\ForgotPassword;
use common\tasks\SendPasswordRecoveryEmail;
use common\tests\unit\TestCase;
use yii\queue\Queue;
class SendPasswordRecoveryEmailTest extends TestCase {
public function testCreateFromConfirmation() {
$account = new Account();
$account->username = 'mock-username';
$account->email = 'mock@ely.by';
$account->lang = 'id';
/** @var \Mockery\Mock|ForgotPassword $confirmation */
$confirmation = mock(ForgotPassword::class)->makePartial();
$confirmation->key = 'ABCDEFG';
$confirmation->shouldReceive('getAccount')->andReturn($account);
$result = SendPasswordRecoveryEmail::createFromConfirmation($confirmation);
$this->assertInstanceOf(SendPasswordRecoveryEmail::class, $result);
$this->assertSame('mock-username', $result->username);
$this->assertSame('mock@ely.by', $result->email);
$this->assertSame('ABCDEFG', $result->code);
$this->assertSame('http://localhost/recover-password/ABCDEFG', $result->link);
$this->assertSame('id', $result->locale);
}
public function testExecute() {
$task = new SendPasswordRecoveryEmail();
$task->username = 'mock-username';
$task->email = 'mock@ely.by';
$task->code = 'GFEDCBA';
$task->link = 'https://account.ely.by/recover-password/ABCDEFG';
$task->locale = 'ru';
$task->execute(mock(Queue::class));
$this->tester->canSeeEmailIsSent(1);
/** @var \yii\swiftmailer\Message $email */
$email = $this->tester->grabSentEmails()[0];
$this->assertSame(['mock@ely.by' => 'mock-username'], $email->getTo());
$this->assertSame('Ely.by Account forgot password', $email->getSubject());
$body = $email->getSwiftMessage()->getBody();
$this->assertContains('Привет, mock-username', $body);
$this->assertContains('GFEDCBA', $body);
$this->assertContains('https://account.ely.by/recover-password/ABCDEFG', $body);
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace common\tests\unit\tasks;
use common\models\Account;
use common\models\confirmations\RegistrationConfirmation;
use common\tasks\SendRegistrationEmail;
use common\tests\unit\TestCase;
use yii\queue\Queue;
class SendRegistrationEmailTest extends TestCase {
public function testCreateFromConfirmation() {
$account = new Account();
$account->username = 'mock-username';
$account->email = 'mock@ely.by';
$account->lang = 'ru';
/** @var \Mockery\Mock|RegistrationConfirmation $confirmation */
$confirmation = mock(RegistrationConfirmation::class)->makePartial();
$confirmation->key = 'ABCDEFG';
$confirmation->shouldReceive('getAccount')->andReturn($account);
$result = SendRegistrationEmail::createFromConfirmation($confirmation);
$this->assertInstanceOf(SendRegistrationEmail::class, $result);
$this->assertSame('mock-username', $result->username);
$this->assertSame('mock@ely.by', $result->email);
$this->assertSame('ABCDEFG', $result->code);
$this->assertSame('http://localhost/activation/ABCDEFG', $result->link);
$this->assertSame('ru', $result->locale);
}
public function testExecute() {
$task = new SendRegistrationEmail();
$task->username = 'mock-username';
$task->email = 'mock@ely.by';
$task->code = 'GFEDCBA';
$task->link = 'https://account.ely.by/activation/ABCDEFG';
$task->locale = 'ru';
$task->execute(mock(Queue::class));
$this->tester->canSeeEmailIsSent(1);
/** @var \yii\swiftmailer\Message $email */
$email = $this->tester->grabSentEmails()[0];
$this->assertSame(['mock@ely.by' => 'mock-username'], $email->getTo());
$this->assertSame('Ely.by Account registration', $email->getSubject());
$body = $email->getSwiftMessage()->getBody();
$this->assertContains('Привет, mock-username', $body);
$this->assertContains('GFEDCBA', $body);
$this->assertContains('https://account.ely.by/activation/ABCDEFG', $body);
}
}

View File

@@ -0,0 +1,140 @@
<?php
namespace common\tests\unit\validators;
use common\validators\EmailValidator;
use common\tests\fixtures\AccountFixture;
use common\tests\helpers\Mock;
use common\tests\unit\TestCase;
use yii\base\Model;
use yii\validators\EmailValidator as YiiEmailValidator;
class EmailValidatorTest extends TestCase {
/**
* @var EmailValidator
*/
private $validator;
public function _before() {
parent::_before();
$this->validator = new EmailValidator();
}
public function testValidateTrimming() {
// Prevent it to access to db
Mock::func(YiiEmailValidator::class, 'checkdnsrr')->andReturn(false);
$model = $this->createModel("testemail@ely.by\u{feff}"); // Zero width no-break space (U+FEFF)
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_invalid'], $model->getErrors('field'));
$this->assertEquals('testemail@ely.by', $model->field);
}
public function testValidateAttributeRequired() {
$model = $this->createModel('');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_required'], $model->getErrors('field'));
$model = $this->createModel('email');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_required'], $model->getErrors('field'));
}
public function testValidateAttributeLength() {
Mock::func(YiiEmailValidator::class, 'checkdnsrr')->andReturnTrue();
$model = $this->createModel(
'emailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemail' .
'emailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemail' .
'emailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemailemail' .
'@gmail.com' // = 256 symbols
);
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_too_long'], $model->getErrors('field'));
$model = $this->createModel('some-email@gmail.com');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_too_long'], $model->getErrors('field'));
}
public function testValidateAttributeEmail() {
Mock::func(YiiEmailValidator::class, 'checkdnsrr')->times(3)->andReturnValues([false, false, true]);
$model = $this->createModel('non-email');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_invalid'], $model->getErrors('field'));
$model = $this->createModel('non-email@etot-domen-ne-suschestrvyet.de');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_invalid'], $model->getErrors('field'));
$model = $this->createModel('valid-email@gmail.com');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_invalid'], $model->getErrors('field'));
}
public function testValidateAttributeTempmail() {
Mock::func(YiiEmailValidator::class, 'checkdnsrr')->times(2)->andReturnTrue();
$model = $this->createModel('ibrpycwyjdnt@dropmail.me');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_is_tempmail'], $model->getErrors('field'));
$model = $this->createModel('valid-email@gmail.com');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_is_tempmail'], $model->getErrors('field'));
}
public function testValidateAttributeIdna() {
Mock::func(YiiEmailValidator::class, 'checkdnsrr')->times(2)->andReturnTrue();
$model = $this->createModel('qdushyantasunassm@❕.gq');
$this->validator->validateAttribute($model, 'field');
$this->assertSame('qdushyantasunassm@xn--bei.gq', $model->field);
$model = $this->createModel('valid-email@gmail.com');
$this->validator->validateAttribute($model, 'field');
$this->assertSame('valid-email@gmail.com', $model->field);
}
public function testValidateAttributeUnique() {
Mock::func(YiiEmailValidator::class, 'checkdnsrr')->times(3)->andReturnTrue();
$this->tester->haveFixtures([
'accounts' => AccountFixture::class,
]);
/** @var \common\models\Account $accountFixture */
$accountFixture = $this->tester->grabFixture('accounts', 'admin');
$model = $this->createModel($accountFixture->email);
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.email_not_available'], $model->getErrors('field'));
$model = $this->createModel($accountFixture->email);
$this->validator->accountCallback = function() use ($accountFixture) {
return $accountFixture->id;
};
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_not_available'], $model->getErrors('field'));
$this->validator->accountCallback = null;
$model = $this->createModel('some-unique-email@gmail.com');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.email_not_available'], $model->getErrors('field'));
}
/**
* @param string $fieldValue
* @return Model
*/
private function createModel(string $fieldValue): Model {
$class = new class extends Model {
public $field;
};
$class->field = $fieldValue;
return $class;
}
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace common\tests\unit\validators;
use common\validators\LanguageValidator;
use common\tests\unit\TestCase;
/**
* @covers \common\validators\LanguageValidator
*/
class LanguageValidatorTest extends TestCase {
/**
* @param string $locale
* @param bool $shouldBeValid
*
* @dataProvider getTestCases
*/
public function testValidate(string $locale, bool $shouldBeValid): void {
$validator = new LanguageValidator();
$result = $validator->validate($locale, $error);
$this->assertSame($shouldBeValid, $result, $locale);
if (!$shouldBeValid) {
$this->assertSame($validator->message, $error);
}
}
public function getTestCases(): array {
return [
// valid
['de', true],
['de_DE', true],
['deu', true],
['en', true],
['en_US', true],
['fil', true],
['fil_PH', true],
['zh', true],
['zh_Hans_CN', true],
['zh_Hant_HK', true],
// invalid
['de_FR', false],
['fr_US', false],
['foo_bar', false],
['foo_bar_baz', false],
];
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace common\tests\unit\validators;
use common\validators\MinecraftServerAddressValidator;
use common\tests\unit\TestCase;
class MinecraftServerAddressValidatorTest extends TestCase {
/**
* @dataProvider domainNames
*/
public function testValidate($address, $shouldBeValid) {
$validator = new MinecraftServerAddressValidator();
$validator->validate($address, $errors);
$this->assertEquals($shouldBeValid, $errors === null);
}
public function domainNames() {
return [
['localhost', true ],
['localhost:25565', true ],
['mc.hypixel.net', true ],
['mc.hypixel.net:25565', true ],
['136.243.88.97', true ],
['136.243.88.97:25565', true ],
['http://ely.by', false],
['http://ely.by:80', false],
['ely.by/abcd', false],
['ely.by?abcd', false],
];
}
}

View File

@@ -0,0 +1,114 @@
<?php
namespace common\tests\unit\validators;
use common\validators\UsernameValidator;
use common\tests\fixtures\AccountFixture;
use common\tests\unit\TestCase;
use yii\base\Model;
class UsernameValidatorTest extends TestCase {
/**
* @var UsernameValidator
*/
private $validator;
public function _before() {
parent::_before();
$this->validator = new UsernameValidator();
}
public function testValidateTrimming() {
$model = $this->createModel("HereIsJohnny#\u{feff}"); // Zero width no-break space (U+FEFF)
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.username_invalid'], $model->getErrors('field'));
$this->assertEquals('HereIsJohnny#', $model->field);
}
public function testValidateAttributeRequired() {
$model = $this->createModel('');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.username_required'], $model->getErrors('field'));
$model = $this->createModel('username');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.username_required'], $model->getErrors('field'));
}
public function testValidateAttributeLength() {
$model = $this->createModel('at');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.username_too_short'], $model->getErrors('field'));
$model = $this->createModel('erickskrauch_erickskrauch');
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.username_too_long'], $model->getErrors('field'));
$model = $this->createModel('username');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.username_too_short'], $model->getErrors('field'));
$this->assertNotEquals(['error.username_too_long'], $model->getErrors('field'));
}
// TODO: rewrite this test with @provider usage
public function testValidateAttributePattern() {
$shouldBeValid = [
'русский_ник', 'русский_ник_на_грани!', 'numbers1132', '*__*-Stars-*__*', '1-_.!$%^&*()[]',
'[ESP]Эрик', 'Свят_помидор;', роблена_ў_беларусі:)',
];
foreach ($shouldBeValid as $nickname) {
$model = $this->createModel($nickname);
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.username_invalid'], $model->getErrors('field'));
}
$shouldBeInvalid = [
'nick@name', 'spaced nick', 'im#hashed', 'quest?ion',
];
foreach ($shouldBeInvalid as $nickname) {
$model = $this->createModel($nickname);
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.username_invalid'], $model->getErrors('field'));
}
}
public function testValidateAttributeUnique() {
$this->tester->haveFixtures([
'accounts' => AccountFixture::class,
]);
/** @var \common\models\Account $accountFixture */
$accountFixture = $this->tester->grabFixture('accounts', 'admin');
$model = $this->createModel($accountFixture->username);
$this->validator->validateAttribute($model, 'field');
$this->assertEquals(['error.username_not_available'], $model->getErrors('field'));
$model = $this->createModel($accountFixture->username);
$this->validator->accountCallback = function() use ($accountFixture) {
return $accountFixture->id;
};
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.username_not_available'], $model->getErrors('field'));
$this->validator->accountCallback = null;
$model = $this->createModel('some-unique-username');
$this->validator->validateAttribute($model, 'field');
$this->assertNotEquals(['error.username_not_available'], $model->getErrors('field'));
}
/**
* @param string $fieldValue
* @return Model
*/
private function createModel(string $fieldValue): Model {
$class = new class extends Model {
public $field;
};
$class->field = $fieldValue;
return $class;
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace common\tests\unit\validators;
use Codeception\Specify;
use common\validators\UuidValidator;
use Faker\Provider\Uuid;
use common\tests\unit\TestCase;
use yii\base\Model;
class UuidValidatorTest extends TestCase {
use Specify;
public function testValidateAttribute() {
$this->specify('expected error if passed empty value', function() {
$validator = new UuidValidator();
$model = $this->createModel();
$validator->validateAttribute($model, 'attribute');
$this->assertTrue($model->hasErrors());
$this->assertEquals(['Attribute must be valid uuid'], $model->getErrors('attribute'));
});
$this->specify('expected error if passed invalid string', function() {
$validator = new UuidValidator();
$model = $this->createModel();
$model->attribute = '123456789';
$validator->validateAttribute($model, 'attribute');
$this->assertTrue($model->hasErrors());
$this->assertEquals(['Attribute must be valid uuid'], $model->getErrors('attribute'));
});
$this->specify('no errors if passed nil uuid and allowNil is set to true', function() {
$validator = new UuidValidator();
$model = $this->createModel();
$model->attribute = '00000000-0000-0000-0000-000000000000';
$validator->validateAttribute($model, 'attribute');
$this->assertFalse($model->hasErrors());
});
$this->specify('no errors if passed nil uuid and allowNil is set to false', function() {
$validator = new UuidValidator();
$validator->allowNil = false;
$model = $this->createModel();
$model->attribute = '00000000-0000-0000-0000-000000000000';
$validator->validateAttribute($model, 'attribute');
$this->assertTrue($model->hasErrors());
$this->assertEquals(['Attribute must be valid uuid'], $model->getErrors('attribute'));
});
$this->specify('no errors if passed valid uuid', function() {
$validator = new UuidValidator();
$model = $this->createModel();
$model->attribute = Uuid::uuid();
$validator->validateAttribute($model, 'attribute');
$this->assertFalse($model->hasErrors());
});
$this->specify('no errors if passed uuid string without dashes and converted to standart value', function() {
$validator = new UuidValidator();
$model = $this->createModel();
$originalUuid = Uuid::uuid();
$model->attribute = str_replace('-', '', $originalUuid);
$validator->validateAttribute($model, 'attribute');
$this->assertFalse($model->hasErrors());
$this->assertEquals($originalUuid, $model->attribute);
});
}
/**
* @return Model
*/
public function createModel() {
return new class extends Model {
public $attribute;
};
}
}