Implemented WebHooks delivery queue.

Completely removed usage of the RabbitMQ. Queue now based on Redis channels.
Worker process now extracted as separate docker container.
Base image upgraded to the 1.8.0 version (PHP 7.2.7 and pcntl extension).
This commit is contained in:
ErickSkrauch
2018-07-08 18:20:19 +03:00
parent 6751eb6591
commit c0aa78d156
55 changed files with 933 additions and 1684 deletions

View File

@@ -4,7 +4,6 @@ modules:
- Filesystem
- Yii2
- tests\codeception\common\_support\FixtureHelper
- tests\codeception\common\_support\amqp\Helper
- tests\codeception\common\_support\Mockery
- Redis
- Asserts

View File

@@ -3,7 +3,6 @@ modules:
enabled:
- Yii2:
part: [orm, email, fixtures]
- tests\codeception\common\_support\amqp\Helper
- tests\codeception\common\_support\queue\CodeceptionQueueHelper
- tests\codeception\common\_support\Mockery
config:

View File

@@ -28,12 +28,6 @@ class ConfirmEmailFormTest extends TestCase {
/** @var Account $account */
$account = Account::findOne($fixture['account_id']);
$this->assertEquals(Account::STATUS_ACTIVE, $account->status, 'user status changed to active');
$message = $this->tester->grabLastSentAmqpMessage('events');
$body = json_decode($message->getBody(), true);
$this->assertEquals($account->id, $body['accountId']);
$this->assertEquals($account->username, $body['newUsername']);
$this->assertNull($body['oldUsername']);
}
private function createModel($key) {

View File

@@ -32,19 +32,6 @@ class ChangeEmailFormTest extends TestCase {
/** @noinspection UnserializeExploitsInspection */
$data = unserialize($newEmailConfirmationFixture['_data']);
$this->assertEquals($data['newEmail'], $account->email);
$this->tester->canSeeAmqpMessageIsCreated('events');
}
public function testCreateTask() {
/** @var Account $account */
$account = Account::findOne($this->getAccountId());
$model = new ChangeEmailForm($account);
$model->createTask(1, 'test1@ely.by', 'test@ely.by');
$message = $this->tester->grabLastSentAmqpMessage('events');
$body = json_decode($message->getBody(), true);
$this->assertEquals(1, $body['accountId']);
$this->assertEquals('test1@ely.by', $body['newEmail']);
$this->assertEquals('test@ely.by', $body['oldEmail']);
}
private function getAccountId() {

View File

@@ -4,6 +4,7 @@ namespace tests\codeception\api\unit\modules\accounts\models;
use api\modules\accounts\models\ChangeUsernameForm;
use common\models\Account;
use common\models\UsernameHistory;
use common\tasks\PullMojangUsername;
use tests\codeception\api\unit\TestCase;
use tests\codeception\common\fixtures\AccountFixture;
use tests\codeception\common\fixtures\UsernameHistoryFixture;
@@ -25,7 +26,10 @@ class ChangeUsernameFormTest extends TestCase {
$this->assertTrue($model->performAction());
$this->assertEquals('my_new_nickname', Account::findOne($this->getAccountId())->username);
$this->assertInstanceOf(UsernameHistory::class, UsernameHistory::findOne(['username' => 'my_new_nickname']));
$this->tester->canSeeAmqpMessageIsCreated('events');
/** @var PullMojangUsername $job */
$job = $this->tester->grabLastQueuedJob();
$this->assertInstanceOf(PullMojangUsername::class, $job);
$this->assertSame($job->username, 'my_new_nickname');
}
public function testPerformActionWithTheSameUsername() {
@@ -42,7 +46,7 @@ class ChangeUsernameFormTest extends TestCase {
'username' => $username,
['>=', 'applied_in', $callTime],
]), 'no new UsernameHistory record, if we don\'t change username');
$this->tester->cantSeeAmqpMessageIsCreated('events');
$this->assertNull($this->tester->grabLastQueuedJob());
}
public function testPerformActionWithChangeCase() {
@@ -58,17 +62,10 @@ class ChangeUsernameFormTest extends TestCase {
UsernameHistory::findOne(['username' => $newUsername]),
'username should change, if we change case of some letters'
);
$this->tester->canSeeAmqpMessageIsCreated('events');
}
public function testCreateTask() {
$model = new ChangeUsernameForm($this->getAccount());
$model->createEventTask(1, 'test1', 'test');
$message = $this->tester->grabLastSentAmqpMessage('events');
$body = json_decode($message->getBody(), true);
$this->assertEquals(1, $body['accountId']);
$this->assertEquals('test1', $body['newUsername']);
$this->assertEquals('test', $body['oldUsername']);
/** @var PullMojangUsername $job */
$job = $this->tester->grabLastQueuedJob();
$this->assertInstanceOf(PullMojangUsername::class, $job);
$this->assertSame($job->username, $newUsername);
}
private function getAccount(): Account {

View File

@@ -4,6 +4,7 @@ namespace tests\codeception\api\unit\modules\internal\models;
use api\modules\accounts\models\BanAccountForm;
use api\modules\internal\helpers\Error as E;
use common\models\Account;
use common\tasks\ClearAccountSessions;
use tests\codeception\api\unit\TestCase;
class BanFormTest extends TestCase {
@@ -35,28 +36,10 @@ class BanFormTest extends TestCase {
$model = new BanAccountForm($account);
$this->assertTrue($model->performAction());
$this->assertEquals(Account::STATUS_BANNED, $account->status);
$this->tester->canSeeAmqpMessageIsCreated('events');
}
public function testCreateTask() {
$account = new Account();
$account->id = 3;
$model = new BanAccountForm($account);
$model->createTask();
$message = json_decode($this->tester->grabLastSentAmqpMessage('events')->body, true);
$this->assertSame(3, $message['accountId']);
$this->assertSame(-1, $message['duration']);
$this->assertSame('', $message['message']);
$model = new BanAccountForm($account);
$model->duration = 123;
$model->message = 'test';
$model->createTask();
$message = json_decode($this->tester->grabLastSentAmqpMessage('events')->body, true);
$this->assertSame(3, $message['accountId']);
$this->assertSame(123, $message['duration']);
$this->assertSame('test', $message['message']);
/** @var ClearAccountSessions $job */
$job = $this->tester->grabLastQueuedJob();
$this->assertInstanceOf(ClearAccountSessions::class, $job);
$this->assertSame($job->accountId, $account->id);
}
}

View File

@@ -36,17 +36,6 @@ class PardonFormTest extends TestCase {
$model = new PardonAccountForm($account);
$this->assertTrue($model->performAction());
$this->assertEquals(Account::STATUS_ACTIVE, $account->status);
$this->tester->canSeeAmqpMessageIsCreated('events');
}
public function testCreateTask() {
$account = new Account();
$account->id = 3;
$model = new PardonAccountForm($account);
$model->createTask();
$message = json_decode($this->tester->grabLastSentAmqpMessage('events')->body, true);
$this->assertSame(3, $message['accountId']);
}
}

View File

@@ -1,91 +0,0 @@
<?php
namespace tests\codeception\common\_support\amqp;
use Codeception\Exception\ModuleException;
use Codeception\Module;
use Codeception\Module\Yii2;
class Helper extends Module {
/**
* Checks that message is created.
*
* ```php
* <?php
* // check that at least 1 message was created
* $I->seeAmqpMessageIsCreated();
*
* // check that only 3 messages were created
* $I->seeAmqpMessageIsCreated(3);
* ```
*
* @param string|null $exchange
* @param int|null $num
*/
public function seeAmqpMessageIsCreated($exchange = null, $num = null) {
if ($num === null) {
$this->assertNotEmpty($this->grabSentAmqpMessages($exchange), 'message were created');
return;
}
$this->assertCount(
$num,
$this->grabSentAmqpMessages($exchange),
'number of created messages is equal to ' . $num
);
}
/**
* Checks that no messages was created
*
* @param string|null $exchange
*/
public function dontSeeAmqpMessageIsCreated($exchange = null) {
$this->seeAmqpMessageIsCreated($exchange, 0);
}
/**
* Returns last sent message
*
* @param string|null $exchange
* @return \PhpAmqpLib\Message\AMQPMessage
*/
public function grabLastSentAmqpMessage($exchange = null) {
$this->seeAmqpMessageIsCreated();
$messages = $this->grabSentAmqpMessages($exchange);
return end($messages);
}
/**
* 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 \PhpAmqpLib\Message\AMQPMessage[]
* @throws ModuleException
*/
public function grabSentAmqpMessages($exchange = null) {
$amqp = $this->grabComponent('amqp');
if (!$amqp instanceof TestComponent) {
throw new ModuleException($this, 'AMQP module is not mocked, can\'t test messages');
}
return $amqp->getSentMessages($exchange);
}
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

@@ -1,58 +0,0 @@
<?php
namespace tests\codeception\common\_support\amqp;
use common\components\RabbitMQ\Component;
use PhpAmqpLib\Connection\AbstractConnection;
class TestComponent extends Component {
private $sentMessages = [];
public function init() {
\yii\base\Component::init();
}
public function getConnection() {
/** @noinspection MagicMethodsValidityInspection */
/** @noinspection PhpMissingParentConstructorInspection */
return new class extends AbstractConnection {
public function __construct(
$user,
$password,
$vhost,
$insist,
$login_method,
$login_response,
$locale,
\PhpAmqpLib\Wire\IO\AbstractIO $io,
$heartbeat
) {
// ничего не делаем
}
};
}
public function sendToExchange($exchangeName, $routingKey, $message, $exchangeArgs = [], $publishArgs = []) {
$this->sentMessages[$exchangeName][] = $this->prepareMessage($message);
}
/**
* @param string|null $exchangeName
* @return \PhpAmqpLib\Message\AMQPMessage[]
*/
public function getSentMessages(string $exchangeName = null): array {
if ($exchangeName !== null) {
return $this->sentMessages[$exchangeName] ?? [];
}
$messages = [];
foreach ($this->sentMessages as $exchangeGroup) {
foreach ($exchangeGroup as $message) {
$messages[] = $message;
}
}
return $messages;
}
}

View File

@@ -14,7 +14,12 @@ class CodeceptionQueueHelper extends Module {
*/
public function grabLastQueuedJob() {
$messages = $this->grabQueueJobs();
return end($messages);
$last = end($messages);
if ($last === false) {
return null;
}
return $last;
}
/**

View File

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

View File

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

View File

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

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

@@ -3,6 +3,7 @@ modules:
enabled:
- Yii2:
part: [orm, email, fixtures]
- tests\codeception\common\_support\queue\CodeceptionQueueHelper
- tests\codeception\common\_support\Mockery
config:
Yii2:

View File

@@ -1,14 +1,20 @@
<?php
declare(strict_types=1);
namespace tests\codeception\common\unit\models;
use Codeception\Specify;
use common\components\UserPass;
use common\models\Account;
use common\tasks\CreateWebHooksDeliveries;
use tests\codeception\common\fixtures\MojangUsernameFixture;
use tests\codeception\common\unit\TestCase;
use Yii;
use const common\LATEST_RULES_VERSION;
/**
* @covers \common\models\Account
*/
class AccountTest extends TestCase {
use Specify;
@@ -119,4 +125,37 @@ class AccountTest extends TestCase {
$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,44 @@
<?php
declare(strict_types=1);
namespace tests\codeception\common\unit\tasks;
use common\models\Account;
use common\tasks\ClearAccountSessions;
use tests\codeception\common\fixtures;
use tests\codeception\common\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,91 @@
<?php
declare(strict_types=1);
namespace tests\codeception\common\unit\tasks;
use common\models\Account;
use common\tasks\CreateWebHooksDeliveries;
use common\tasks\DeliveryWebHook;
use tests\codeception\common\fixtures;
use tests\codeception\common\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,132 @@
<?php
declare(strict_types=1);
namespace tests\codeception\common\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 tests\codeception\common\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

@@ -1,30 +1,32 @@
<?php
namespace codeception\console\unit\controllers;
declare(strict_types=1);
namespace tests\codeception\common\unit\tasks;
use common\components\Mojang\Api;
use common\components\Mojang\exceptions\NoContentException;
use common\components\Mojang\response\UsernameToUUIDResponse;
use common\models\amqp\AccountBanned;
use common\models\amqp\UsernameChanged;
use common\models\Account;
use common\models\MojangUsername;
use console\controllers\AccountQueueController;
use tests\codeception\common\fixtures\AccountFixture;
use common\tasks\PullMojangUsername;
use tests\codeception\common\fixtures\MojangUsernameFixture;
use tests\codeception\console\unit\TestCase;
use Yii;
use tests\codeception\common\unit\TestCase;
use yii\queue\Queue;
class AccountQueueControllerTest extends TestCase {
/**
* @var AccountQueueController
*/
private $controller;
/**
* @covers \common\tasks\PullMojangUsername
*/
class PullMojangUsernameTest extends TestCase {
private $expectedResponse;
/**
* @var PullMojangUsername
*/
private $task;
public function _fixtures() {
return [
'accounts' => AccountFixture::class,
'mojangUsernames' => MojangUsernameFixture::class,
];
}
@@ -32,10 +34,9 @@ class AccountQueueControllerTest extends TestCase {
public function _before() {
parent::_before();
/** @var AccountQueueController|\PHPUnit_Framework_MockObject_MockObject $controller */
$controller = $this->getMockBuilder(AccountQueueController::class)
/** @var PullMojangUsername|\PHPUnit_Framework_MockObject_MockObject $task */
$task = $this->getMockBuilder(PullMojangUsername::class)
->setMethods(['createMojangApi'])
->setConstructorArgs(['account-queue', Yii::$app])
->getMock();
/** @var Api|\PHPUnit_Framework_MockObject_MockObject $apiMock */
@@ -54,30 +55,31 @@ class AccountQueueControllerTest extends TestCase {
return $this->expectedResponse;
});
$controller
$task
->expects($this->any())
->method('createMojangApi')
->willReturn($apiMock);
$this->controller = $controller;
$this->task = $task;
}
public function testRouteUsernameChangedUsernameExists() {
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\Account $accountInfo */
$accountInfo = $this->tester->grabFixture('accounts', 'admin');
/** @var MojangUsername $mojangUsernameFixture */
/** @var \common\models\MojangUsername $mojangUsernameFixture */
$mojangUsernameFixture = $this->tester->grabFixture('mojangUsernames', 'Notch');
$body = new UsernameChanged([
'accountId' => $accountInfo->id,
'oldUsername' => $accountInfo->username,
'newUsername' => 'Notch',
]);
$this->controller->routeUsernameChanged($body);
$this->task->username = 'Notch';
$this->task->execute(mock(Queue::class));
/** @var MojangUsername|null $mojangUsername */
$mojangUsername = MojangUsername::findOne('Notch');
$this->assertInstanceOf(MojangUsername::class, $mojangUsername);
@@ -85,81 +87,62 @@ class AccountQueueControllerTest extends TestCase {
$this->assertLessThanOrEqual(time(), $mojangUsername->last_pulled_at);
}
public function testRouteUsernameChangedUsernameNotExists() {
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;
/** @var \common\models\Account $accountInfo */
$accountInfo = $this->tester->grabFixture('accounts', 'admin');
$body = new UsernameChanged([
'accountId' => $accountInfo['id'],
'oldUsername' => $accountInfo['username'],
'newUsername' => 'Chest',
]);
$this->controller->routeUsernameChanged($body);
$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 testRouteUsernameChangedRemoveIfExistsNoMore() {
public function testExecuteRemoveIfExistsNoMore() {
$this->expectedResponse = false;
/** @var \common\models\Account $accountInfo */
$accountInfo = $this->tester->grabFixture('accounts', 'admin');
$username = $this->tester->grabFixture('mojangUsernames', 'not-exists')['username'];
$body = new UsernameChanged([
'accountId' => $accountInfo['id'],
'oldUsername' => $accountInfo['username'],
'newUsername' => $username,
]);
$this->controller->routeUsernameChanged($body);
$this->task->username = $username;
$this->task->execute(mock(Queue::class));
/** @var MojangUsername|null $mojangUsername */
$mojangUsername = MojangUsername::findOne($username);
$this->assertNull($mojangUsername);
}
public function testRouteUsernameChangedUuidUpdated() {
public function testExecuteUuidUpdated() {
$expectedResponse = new UsernameToUUIDResponse();
$expectedResponse->id = 'f498513ce8c84773be26ecfc7ed5185d';
$expectedResponse->name = 'jeb';
$this->expectedResponse = $expectedResponse;
/** @var \common\models\Account $accountInfo */
$accountInfo = $this->tester->grabFixture('accounts', 'admin');
/** @var MojangUsername $mojangInfo */
$mojangInfo = $this->tester->grabFixture('mojangUsernames', 'uuid-changed');
$username = $mojangInfo['username'];
$body = new UsernameChanged([
'accountId' => $accountInfo['id'],
'oldUsername' => $accountInfo['username'],
'newUsername' => $username,
]);
$this->controller->routeUsernameChanged($body);
$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);
}
public function testRouteAccountBanned() {
/** @var \common\models\Account $bannedAccount */
$bannedAccount = $this->tester->grabFixture('accounts', 'banned-account');
$this->tester->haveFixtures([
'oauthSessions' => \tests\codeception\common\fixtures\OauthSessionFixture::class,
'minecraftAccessKeys' => \tests\codeception\common\fixtures\MinecraftAccessKeyFixture::class,
'authSessions' => \tests\codeception\common\fixtures\AccountSessionFixture::class,
]);
$body = new AccountBanned();
$body->accountId = $bannedAccount->id;
$this->controller->routeAccountBanned($body);
$this->assertEmpty($bannedAccount->sessions);
$this->assertEmpty($bannedAccount->minecraftAccessKeys);
$this->assertEmpty($bannedAccount->oauthSessions);
}
}

View File

@@ -20,9 +20,6 @@ return [
// Для тестов нам не сильно важна безопасность, а вот время прохождения тестов значительно сокращается
'passwordHashCost' => 4,
],
'amqp' => [
'class' => tests\codeception\common\_support\amqp\TestComponent::class,
],
'queue' => [
'class' => tests\codeception\common\_support\queue\Queue::class,
],