![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/framework/Webapi/Test/Unit/ |
<?php /** * Test Webapi Error Processor. * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ declare(strict_types=1); namespace Magento\Framework\Webapi\Test\Unit; use Magento\Framework\App\State; use Magento\Framework\Exception\AuthorizationException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Filesystem; use Magento\Framework\Json\Encoder; use Magento\Framework\Phrase; use Magento\Framework\Webapi\ErrorProcessor; use Magento\Framework\Webapi\Exception as WebapiException; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ErrorProcessorTest extends TestCase { /** @var ErrorProcessor */ protected $_errorProcessor; /** @var Encoder */ protected $encoderMock; /** @var MockObject */ protected $_appStateMock; /** @var LoggerInterface */ protected $_loggerMock; protected function setUp(): void { /** Set up mocks for SUT. */ $this->encoderMock = $this->getMockBuilder(Encoder::class) ->disableOriginalConstructor() ->setMethods(['encode']) ->getMock(); $this->_appStateMock = $this->getMockBuilder(State::class) ->disableOriginalConstructor() ->getMock(); $this->_loggerMock = $this->getMockBuilder(LoggerInterface::class) ->getMock(); $filesystemMock = $this->getMockBuilder(Filesystem::class) ->disableOriginalConstructor() ->getMock(); /** Initialize SUT. */ $this->_errorProcessor = new ErrorProcessor( $this->encoderMock, $this->_appStateMock, $this->_loggerMock, $filesystemMock ); parent::setUp(); } protected function tearDown(): void { unset($this->_errorProcessor); unset($this->encoderMock); unset($this->_appStateMock); parent::tearDown(); } /** * Test render method in JSON format. * * @return void */ public function testRenderJson() { $_SERVER['HTTP_ACCEPT'] = 'json'; /** Assert that jsonEncode method will be executed once. */ $this->encoderMock->expects( $this->once() )->method( 'encode' )->willReturnCallback( [$this, 'callbackJsonEncode'], $this->returnArgument(0) ); /** Init output buffering to catch output via echo function. */ ob_start(); $this->_errorProcessor->renderErrorMessage('Message'); /** Get output buffer. */ $actualResult = ob_get_contents(); ob_end_clean(); $expectedResult = '{"messages":{"error":[{"code":500,"message":"Message"}]}}'; $this->assertEquals($expectedResult, $actualResult, 'Invalid rendering in JSON.'); } /** * Callback function for RenderJson and RenderJsonInDeveloperMode tests. * * Method encodes data to JSON and returns it. * * @param array $data * @return string */ public function callbackJsonEncode($data) { return json_encode($data); } /** * Test render method in JSON format with turned on developer mode. * @return void */ public function testRenderJsonInDeveloperMode() { $_SERVER['HTTP_ACCEPT'] = 'json'; /** Mock app to return enabled developer mode flag. */ $this->_appStateMock->expects($this->any())->method('getMode')->willReturn('developer'); /** Assert that jsonEncode method will be executed once. */ $this->encoderMock->expects( $this->once() )->method( 'encode' )->willReturnCallback( [$this, 'callbackJsonEncode'], $this->returnArgument(0) ); ob_start(); $this->_errorProcessor->renderErrorMessage('Message', 'Message trace.', 401); $actualResult = ob_get_contents(); ob_end_clean(); $expectedResult = '{"messages":{"error":[{"code":401,"message":"Message","trace":"Message trace."}]}}'; $this->assertEquals($expectedResult, $actualResult, 'Invalid rendering in JSON.'); } /** * Test render method in XML format. * @return void */ public function testRenderXml() { $_SERVER['HTTP_ACCEPT'] = 'xml'; /** Init output buffering to catch output via echo function. */ ob_start(); $this->_errorProcessor->renderErrorMessage('Message'); /** Get output buffer. */ $actualResult = ob_get_contents(); ob_end_clean(); $expectedResult = '<?xml version="1.0"?><error><messages><error><data_item><code>500</code>' . '<message><![CDATA[Message]]></message></data_item></error></messages></error>'; $this->assertEquals($expectedResult, $actualResult, 'Invalid rendering in XML.'); } /** * Test render method in XML format with turned on developer mode. * @return void */ public function testRenderXmlInDeveloperMode() { $_SERVER['HTTP_ACCEPT'] = 'xml'; /** Mock app to return enabled developer mode flag. */ $this->_appStateMock->expects($this->any())->method('getMode')->willReturn('developer'); /** Init output buffering to catch output via echo function. */ ob_start(); $this->_errorProcessor->renderErrorMessage('Message', 'Trace message.', 401); /** Get output buffer. */ $actualResult = ob_get_contents(); ob_end_clean(); $expectedResult = '<?xml version="1.0"?><error><messages><error><data_item><code>401</code><message>' . '<![CDATA[Message]]></message><trace><![CDATA[Trace message.]]></trace></data_item></error>' . '</messages></error>'; $this->assertEquals($expectedResult, $actualResult, 'Invalid rendering in XML with turned on developer mode.'); } /** * Test default render format is JSON. * @return void */ public function testRenderDefaultFormat() { /** Set undefined rendering format. */ $_SERVER['HTTP_ACCEPT'] = 'undefined'; /** Assert that jsonEncode method will be executed at least once. */ $this->encoderMock->expects($this->atLeastOnce())->method('encode'); $this->_errorProcessor->renderErrorMessage('Message'); } /** * Test maskException method with turned on developer mode. * @return void */ public function testMaskExceptionInDeveloperMode() { /** Mock app isDeveloperMode to return true. */ $this->_appStateMock->expects($this->once())->method('getMode')->willReturn('developer'); /** Init Logical exception. */ $errorMessage = 'Error Message'; $logicalException = new \LogicException($errorMessage); /** Assert that Logic exception is converted to WebapiException without message obfuscation. */ $maskedException = $this->_errorProcessor->maskException($logicalException); $this->assertInstanceOf(\Magento\Framework\Webapi\Exception::class, $maskedException); $this->assertEquals( $errorMessage, $maskedException->getMessage(), 'Exception was masked incorrectly in developer mode.' ); } /** * Test sendResponse method with various exceptions * * @param \Exception $exception * @param int $expectedHttpCode * @param string $expectedMessage * @param array $expectedDetails * @return void * @dataProvider dataProviderForSendResponseExceptions */ public function testMaskException($exception, $expectedHttpCode, $expectedMessage, $expectedDetails) { /** Assert that exception was logged. */ // TODO:MAGETWO-21077 $this->_loggerMock->expects($this->once())->method('critical'); $maskedException = $this->_errorProcessor->maskException($exception); $this->assertMaskedException( $maskedException, $expectedHttpCode, $expectedMessage, $expectedDetails ); } /** * Test logged exception is the same as the thrown one in production mode */ public function testCriticalExceptionStackTrace() { $thrownException = new \Exception('', 0); $this->_loggerMock->expects($this->once()) ->method('critical') ->willReturnCallback( function (\Exception $loggedException) use ($thrownException) { $this->assertSame($thrownException, $loggedException->getPrevious()); } ); $this->_errorProcessor->maskException($thrownException); } /** * @return array */ public function dataProviderForSendResponseExceptions() { return [ 'NoSuchEntityException' => [ new NoSuchEntityException( new Phrase( 'No such entity with %fieldName = %fieldValue, %field2Name = %field2Value', [ 'fieldName' => 'detail1', 'fieldValue' => 'value1', 'field2Name' => 'resource_id', 'field2Value' => 'resource10', ] ) ), \Magento\Framework\Webapi\Exception::HTTP_NOT_FOUND, 'No such entity with %fieldName = %fieldValue, %field2Name = %field2Value', [ 'fieldName' => 'detail1', 'fieldValue' => 'value1', 'field2Name' => 'resource_id', 'field2Value' => 'resource10', ], ], 'NoSuchEntityException (Empty message)' => [ new NoSuchEntityException(), WebapiException::HTTP_NOT_FOUND, 'No such entity.', [], ], 'AuthorizationException' => [ new AuthorizationException( new Phrase( 'Consumer %consumer_id is not authorized to access %resources', ['consumer_id' => '3', 'resources' => '4'] ) ), WebapiException::HTTP_UNAUTHORIZED, 'Consumer %consumer_id is not authorized to access %resources', ['consumer_id' => '3', 'resources' => '4'], ], 'Exception' => [ new \Exception('Non service exception', 5678), WebapiException::HTTP_INTERNAL_ERROR, 'Internal Error. Details are available in Magento log file. Report ID:', [], ] ]; } /** * Assert that masked exception contains expected data. * * @param \Exception $maskedException * @param int $expectedHttpCode * @param string $expectedMessage * @param array $expectedDetails * @return void */ public function assertMaskedException( $maskedException, $expectedHttpCode, $expectedMessage, $expectedDetails ) { /** All masked exceptions must be WebapiException */ $expectedType = \Magento\Framework\Webapi\Exception::class; $this->assertInstanceOf( $expectedType, $maskedException, "Masked exception type is invalid: expected '{$expectedType}', given '" . get_class( $maskedException ) . "'." ); /** @var $maskedException WebapiException */ $this->assertEquals( $expectedHttpCode, $maskedException->getHttpCode(), "Masked exception HTTP code is invalid: expected '{$expectedHttpCode}', " . "given '{$maskedException->getHttpCode()}'." ); $this->assertStringContainsString( $expectedMessage, $maskedException->getMessage(), "Masked exception message is invalid: expected '{$expectedMessage}', " . "given '{$maskedException->getMessage()}'." ); $this->assertEquals($expectedDetails, $maskedException->getDetails(), "Masked exception details are invalid."); } }