Skip to content

Cover AmqpStore module with unit tests #30660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: 2.4-develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
class Exchange
{
/**
* @var StoreManagerInterface
* @var EnvelopeFactory
*/
private $storeManager;
private $envelopeFactory;

/**
* @var EnvelopeFactory
* @var StoreManagerInterface
*/
private $envelopeFactory;
private $storeManager;

/**
* @var LoggerInterface
Expand All @@ -49,8 +49,8 @@ public function __construct(
StoreManagerInterface $storeManager,
LoggerInterface $logger
) {
$this->storeManager = $storeManager;
$this->envelopeFactory = $envelopeFactory;
$this->storeManager = $storeManager;
$this->logger = $logger;
}

Expand Down Expand Up @@ -83,9 +83,6 @@ public function beforeEnqueue(SubjectExchange $subject, $topic, array $envelopes
$updatedEnvelopes = [];
foreach ($envelopes as $envelope) {
$properties = $envelope->getProperties();
if (!isset($properties)) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$properties = [];
}
if (isset($properties['application_headers'])) {
$headers = $properties['application_headers'];
if ($headers instanceof AMQPTable) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\AmqpStore\Test\Unit\Plugin\AsynchronousOperations;

use Magento\AmqpStore\Plugin\AsynchronousOperations\MassConsumerEnvelopeCallback;
use Magento\AsynchronousOperations\Model\MassConsumerEnvelopeCallback as SubjectMassConsumerEnvelopeCallback;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\MessageQueue\EnvelopeFactory;
use Magento\Framework\MessageQueue\EnvelopeInterface;
use Magento\Framework\MessageQueue\QueueInterface;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;
use PhpAmqpLib\Wire\AMQPTable;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class MassConsumerEnvelopeCallbackTest extends TestCase
{
/**
* @var MassConsumerEnvelopeCallback
*/
private $massConsumerEnvelopeCallbackPlugin;

/**
* @var EnvelopeFactory|MockObject
*/
private $envelopeFactoryMock;

/**
* @var StoreManagerInterface|MockObject
*/
private $storeManagerMock;

/**
* @var \Psr\Log\LoggerInterface|MockObject
*/
private $loggerMock;

/**
* @var SubjectMassConsumerEnvelopeCallback|MockObject
*/
private $subjectMassConsumerEnvelopeCallbackMock;

/**
* @var EnvelopeInterface|MockObject
*/
private $messageMock;

/**
* @var Store|MockObject
*/
private $storeMock;

protected function setUp(): void
{
$this->subjectMassConsumerEnvelopeCallbackMock = $this->createMock(SubjectMassConsumerEnvelopeCallback::class);
$this->storeMock = $this->createMock(Store::class);
$this->messageMock = $this->getMockForAbstractClass(EnvelopeInterface::class);

$this->envelopeFactoryMock = $this->createMock(EnvelopeFactory::class);
$this->storeManagerMock = $this->getMockForAbstractClass(StoreManagerInterface::class);
$this->loggerMock = $this->getMockForAbstractClass(\Psr\Log\LoggerInterface::class);

$objectManager = new ObjectManager($this);
$this->massConsumerEnvelopeCallbackPlugin = $objectManager->getObject(
MassConsumerEnvelopeCallback::class,
[
'envelopeFactory' => $this->envelopeFactoryMock,
'storeManager' => $this->storeManagerMock,
'logger' => $this->loggerMock,
]
);
}

public function testAroundExecuteWhenApplicationHeadersDoesNotExist()
{
$this->messageMock->expects($this->once())
->method('getProperties')
->willReturn(null);

$isProceedCalled = false;
$proceed = function ($message) use (&$isProceedCalled) {
$isProceedCalled = !!$message;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think !!$message is a good option for marking if $proceed was called. Simply true is good enough.

Suggested change
$isProceedCalled = !!$message;
$isProceedCalled = true;

Copy link
Author

@mbvb1223 mbvb1223 Nov 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestion.

In this case, if I use $isProceedCalled = true; then $message is not used anywhere and can be warned a coding convention (and maybe I need to use // @SuppressWarnings(PHPMD.UnusedFormalParameter)).

Also, I want to confirm that $message was put as a parameter on $proceed($message);

Ak, maybe it is better if we change to $isProceedCalled = ($message instanceof EnvelopeInterface);

Haha, it is the same :D
I will leave the code as-is.

};

$this->massConsumerEnvelopeCallbackPlugin->aroundExecute(
$this->subjectMassConsumerEnvelopeCallbackMock,
$proceed,
$this->messageMock
);

$this->assertTrue($isProceedCalled);
}

public function testAroundExecuteWhenCanNotGetCurrentStoreId()
{
$storeId = 333;
$headers = ['store_id' => $storeId];

$amqpProperties = ['application_headers' => $headers];
$this->messageMock->expects($this->once())
->method('getProperties')
->willReturn($amqpProperties);

$message = 'no_such_entity_exception';
$this->storeManagerMock
->expects($this->once())
->method('getStore')
->willThrowException(new NoSuchEntityException(__($message)));

$this->loggerMock
->expects($this->once())
->method('error')
->with("Can't set currentStoreId during processing queue. Message rejected. Error $message.");

$queue = $this->getMockBuilder(QueueInterface::class)
->disableOriginalConstructor()
->getMockForAbstractClass();
$this->subjectMassConsumerEnvelopeCallbackMock
->expects($this->once())
->method('getQueue')
->willReturn($queue);
$queue
->expects($this->once())
->method('reject')
->with($this->messageMock, false, $message);

$isProceedCalled = false;
$proceed = function ($message) use (&$isProceedCalled) {
$isProceedCalled = !!$message;
};

$this->massConsumerEnvelopeCallbackPlugin->aroundExecute(
$this->subjectMassConsumerEnvelopeCallbackMock,
$proceed,
$this->messageMock
);

$this->assertFalse($isProceedCalled);
}

/**
* @dataProvider provideApplicationHeadersForAroundExecuteSuccess
*
* @param array|AMQPTable $headers
* @param int $storeId
* @param int $currentStoreId
*/
public function testAroundExecuteWhenSuccess($headers, int $storeId, int $currentStoreId)
{
$amqpProperties = ['application_headers' => $headers];
$this->messageMock->expects($this->once())
->method('getProperties')
->willReturn($amqpProperties);

$this->storeManagerMock->expects($this->once())
->method('getStore')
->willReturn($this->storeMock);
$this->storeMock->expects($this->once())
->method('getId')
->willReturn($currentStoreId);

$this->storeManagerMock->expects($this->exactly(2))
->method('setCurrentStore')
->withConsecutive(
[$storeId],
[$currentStoreId]
);

$isProceedCalled = false;
$proceed = function ($message) use (&$isProceedCalled) {
$isProceedCalled = !!$message;
};

$this->massConsumerEnvelopeCallbackPlugin->aroundExecute(
$this->subjectMassConsumerEnvelopeCallbackMock,
$proceed,
$this->messageMock
);

$this->assertTrue($isProceedCalled);
}

public function provideApplicationHeadersForAroundExecuteSuccess()
{
$storeId = 123;
$currentStoreId = 99;

return [
[['store_id' => 123], $storeId, $currentStoreId],
[new AMQPTable(['store_id' => 123]), $storeId, $currentStoreId],
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a new object AMQPTable because I could not create a mock and mock for the final method "getNativeData"

Do you have any suggestions for this?

https://github.com/mbvb1223/magento2/blob/1e675494b29424bed5d2183e85b4f619cf6e4c47/app/code/Magento/AmqpStore/Plugin/AsynchronousOperations/MassConsumerEnvelopeCallback.php#L75

];
}
}
Loading