-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
540 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\Exception; | ||
|
||
/** | ||
* Exception thrown when invalid argument is passed while creating domain model. | ||
*/ | ||
class InvalidDomainModelArgumentException extends AbstractMatejException | ||
{ | ||
public static function forInconsistentNumberOfCommands( | ||
int $numberOfCommands, | ||
int $commandResponsesCount | ||
): self { | ||
return new self( | ||
sprintf( | ||
'Provided numberOfCommands (%d) is inconsistent with actual count of command responses (%d)', | ||
$numberOfCommands, | ||
$commandResponsesCount | ||
) | ||
); | ||
} | ||
|
||
public static function forInconsistentNumbersOfCommandProperties( | ||
int $numberOfCommands, | ||
$numberOfSuccessfulCommands, | ||
$numberOfFailedCommands | ||
): self { | ||
return new self( | ||
sprintf( | ||
'Provided numberOfCommands (%d) is inconsistent with provided sum of ' | ||
. 'numberOfSuccessfulCommands (%d) and numberOfFailedCommands (%d)', | ||
$numberOfCommands, | ||
$numberOfSuccessfulCommands, | ||
$numberOfFailedCommands | ||
) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\Exception; | ||
|
||
use Psr\Http\Message\ResponseInterface; | ||
|
||
/** | ||
* Exception thrown when Matej response cannot be decoded. | ||
*/ | ||
class ResponseDecodingException extends AbstractMatejException | ||
{ | ||
public static function forJsonError(string $jsonErrorMsg, ResponseInterface $response): self | ||
{ | ||
return new self( | ||
sprintf( | ||
"Error decoding Matej response: %s\n\nStatus code: %s %s\nBody:\n%s", | ||
$jsonErrorMsg, | ||
$response->getStatusCode(), | ||
$response->getReasonPhrase(), | ||
$response->getBody() | ||
) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\Http; | ||
|
||
use Lmc\Matej\Exception\ResponseDecodingException; | ||
use Lmc\Matej\Model\Response; | ||
use Psr\Http\Message\ResponseInterface; | ||
|
||
class ResponseDecoder implements ResponseDecoderInterface | ||
{ | ||
public function decode(ResponseInterface $httpResponse): Response | ||
{ | ||
$responseData = json_decode($httpResponse->getBody()->getContents()); | ||
|
||
if (JSON_ERROR_NONE !== json_last_error()) { | ||
throw ResponseDecodingException::forJsonError(json_last_error_msg(), $httpResponse); | ||
} | ||
|
||
return new Response( | ||
(int) $responseData->commands->number_of_commands, | ||
(int) $responseData->commands->number_of_successful_commands, | ||
(int) $responseData->commands->number_of_failed_commands, | ||
$responseData->commands->responses | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\Http; | ||
|
||
use Lmc\Matej\Model\Response; | ||
use Psr\Http\Message\ResponseInterface; | ||
|
||
interface ResponseDecoderInterface | ||
{ | ||
public function decode(ResponseInterface $httpResponse): Response; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\Model; | ||
|
||
use Lmc\Matej\Exception\InvalidDomainModelArgumentException; | ||
|
||
/** | ||
* Response to one single command which was part of request batch. | ||
*/ | ||
class CommandResponse | ||
{ | ||
const STATUS_OK = 'OK'; | ||
const STATUS_ERROR = 'ERROR'; | ||
const STATUS_SKIPPED = 'SKIPPED'; | ||
|
||
/** @var string */ | ||
private $status; | ||
/** @var string */ | ||
private $message; | ||
/** @var array */ | ||
private $data = []; | ||
|
||
private function __construct() | ||
{ | ||
} | ||
|
||
public static function createFromRawCommandResponseObject(\stdClass $rawCommandResponseObject): self | ||
{ | ||
if (!isset($rawCommandResponseObject->status)) { | ||
throw new InvalidDomainModelArgumentException('Status field is missing in command response object'); | ||
} | ||
|
||
$commandResponse = new self(); | ||
$commandResponse->status = $rawCommandResponseObject->status; | ||
$commandResponse->message = $rawCommandResponseObject->message ?? ''; | ||
$commandResponse->data = $rawCommandResponseObject->data ?? []; | ||
|
||
return $commandResponse; | ||
} | ||
|
||
public function getStatus(): string | ||
{ | ||
return $this->status; | ||
} | ||
|
||
public function getMessage(): string | ||
{ | ||
return $this->message; | ||
} | ||
|
||
public function getData(): array | ||
{ | ||
return $this->data; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\Model; | ||
|
||
use Lmc\Matej\Exception\InvalidDomainModelArgumentException; | ||
|
||
class Response | ||
{ | ||
/** @var CommandResponse[] */ | ||
private $commandResponses = []; | ||
/** @var int */ | ||
private $numberOfCommands; | ||
/** @var int */ | ||
private $numberOfSuccessfulCommands; | ||
/** @var int */ | ||
private $numberOfFailedCommands; | ||
|
||
public function __construct( | ||
int $numberOfCommands, | ||
int $numberOfSuccessfulCommands, | ||
int $numberOfFailedCommands, | ||
array $commandResponses = [] | ||
) { | ||
$this->numberOfCommands = $numberOfCommands; | ||
$this->numberOfSuccessfulCommands = $numberOfSuccessfulCommands; | ||
$this->numberOfFailedCommands = $numberOfFailedCommands; | ||
|
||
foreach ($commandResponses as $rawCommandResponse) { | ||
$this->commandResponses[] = CommandResponse::createFromRawCommandResponseObject($rawCommandResponse); | ||
} | ||
|
||
if ($this->numberOfCommands !== count($commandResponses)) { | ||
throw InvalidDomainModelArgumentException::forInconsistentNumberOfCommands( | ||
$this->numberOfCommands, | ||
count($commandResponses) | ||
); | ||
} | ||
|
||
if ($this->numberOfCommands !== ($this->numberOfSuccessfulCommands + $this->numberOfFailedCommands)) { | ||
throw InvalidDomainModelArgumentException::forInconsistentNumbersOfCommandProperties( | ||
$this->numberOfCommands, | ||
$this->numberOfSuccessfulCommands, | ||
$this->numberOfFailedCommands | ||
); | ||
} | ||
} | ||
|
||
public function getNumberOfCommands(): int | ||
{ | ||
return $this->numberOfCommands; | ||
} | ||
|
||
public function getNumberOfSuccessfulCommands(): int | ||
{ | ||
return $this->numberOfSuccessfulCommands; | ||
} | ||
|
||
public function getNumberOfFailedCommands(): int | ||
{ | ||
return $this->numberOfFailedCommands; | ||
} | ||
|
||
/** | ||
* Each Command which was part of request batch has here corresponding CommandResponse - on the same index on which | ||
* the Command was added to the request batch. | ||
* | ||
* @return CommandResponse[] | ||
*/ | ||
public function getCommandResponses(): array | ||
{ | ||
return $this->commandResponses; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> | ||
<html><head> | ||
<title>404 Not Found</title> | ||
</head><body> | ||
<h1>Not Found</h1> | ||
<p>The requested URL /foo was not found on this server.</p> | ||
</body></html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"commands": { | ||
"number_of_commands": 3, | ||
"number_of_failed_commands": 1, | ||
"number_of_successful_commands": 2, | ||
"responses": [ | ||
{ | ||
"data": [], | ||
"message": "", | ||
"status": "OK" | ||
}, | ||
{ | ||
"data": [], | ||
"message": "DuplicateKeyError(u'E11000 duplicate key error collection: foo.data_items_properties index: property_1 dup key: { : \"title\" }',)", | ||
"status": "ERROR" | ||
}, | ||
{ | ||
"data": [], | ||
"message": "", | ||
"status": "OK" | ||
} | ||
] | ||
}, | ||
"message": "", | ||
"status": "OK" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"commands": { | ||
"number_of_commands": 1, | ||
"number_of_failed_commands": 0, | ||
"number_of_successful_commands": 1, | ||
"responses": [ | ||
{ | ||
"data": [], | ||
"message": "", | ||
"status": "OK" | ||
} | ||
] | ||
}, | ||
"message": "", | ||
"status": "OK" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace Lmc\Matej\Http; | ||
|
||
use Fig\Http\Message\StatusCodeInterface; | ||
use GuzzleHttp\Psr7\Response; | ||
use Lmc\Matej\Exception\ResponseDecodingException; | ||
use Lmc\Matej\Model\CommandResponse; | ||
use PHPUnit\Framework\TestCase; | ||
use Psr\Http\Message\ResponseInterface; | ||
|
||
class ResponseDecoderTest extends TestCase | ||
{ | ||
/** @var ResponseDecoder */ | ||
protected $decoder; | ||
|
||
/** @before */ | ||
public function init(): void | ||
{ | ||
$this->decoder = new ResponseDecoder(); | ||
} | ||
|
||
/** @test */ | ||
public function shouldDecodeSimpleOkResponse(): void | ||
{ | ||
$response = $this->createJsonResponseFromFile(__DIR__ . '/Fixtures/response-one-successful-command.json'); | ||
|
||
$output = $this->decoder->decode($response); | ||
|
||
$this->assertSame(1, $output->getNumberOfCommands()); | ||
$this->assertSame(1, $output->getNumberOfSuccessfulCommands()); | ||
$this->assertSame(0, $output->getNumberOfFailedCommands()); | ||
|
||
$commandResponses = $output->getCommandResponses(); | ||
$this->assertCount(1, $commandResponses); | ||
$this->assertInstanceOf(CommandResponse::class, $commandResponses[0]); | ||
$this->assertSame(CommandResponse::STATUS_OK, $commandResponses[0]->getStatus()); | ||
} | ||
|
||
/** @test */ | ||
public function shouldDecodeResponseMultipleResponses(): void | ||
{ | ||
$response = $this->createJsonResponseFromFile(__DIR__ . '/Fixtures/response-item-properties.json'); | ||
|
||
$output = $this->decoder->decode($response); | ||
|
||
$this->assertSame(3, $output->getNumberOfCommands()); | ||
$this->assertSame(2, $output->getNumberOfSuccessfulCommands()); | ||
$this->assertSame(1, $output->getNumberOfFailedCommands()); | ||
|
||
$commandResponses = $output->getCommandResponses(); | ||
$this->assertCount(3, $commandResponses); | ||
$this->assertContainsOnlyInstancesOf(CommandResponse::class, $commandResponses); | ||
$this->assertSame(CommandResponse::STATUS_OK, $commandResponses[0]->getStatus()); | ||
$this->assertSame(CommandResponse::STATUS_ERROR, $commandResponses[1]->getStatus()); | ||
$this->assertSame(CommandResponse::STATUS_OK, $commandResponses[2]->getStatus()); | ||
} | ||
|
||
/** @test */ | ||
public function shouldThrowExceptionWhenDecodingFails(): void | ||
{ | ||
$notJsonData = file_get_contents(__DIR__ . '/Fixtures/invalid-json.html'); | ||
$response = new Response(StatusCodeInterface::STATUS_NOT_FOUND, [], $notJsonData); | ||
|
||
$this->expectException(ResponseDecodingException::class); | ||
$this->expectExceptionMessage('Error decoding Matej response'); | ||
$this->expectExceptionMessage('Status code: 404 Not Found'); | ||
$this->expectExceptionMessage('<p>The requested URL /foo was not found on this server.</p>'); | ||
$this->decoder->decode($response); | ||
} | ||
|
||
private function createJsonResponseFromFile(string $fileName): ResponseInterface | ||
{ | ||
$jsonData = file_get_contents($fileName); | ||
$response = new Response(StatusCodeInterface::STATUS_OK, ['Content-Type' => 'application/json'], $jsonData); | ||
|
||
return $response; | ||
} | ||
} |
Oops, something went wrong.