Skip to content

Commit 97c4209

Browse files
authored
Improve (#10)
1 parent 082827b commit 97c4209

File tree

8 files changed

+292
-52
lines changed

8 files changed

+292
-52
lines changed

behat.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ default:
22
suites:
33
default:
44
contexts:
5+
- Tests\Functional\BehatContext\StandaloneContext: ~
56
- Tests\Functional\BehatContext\FeatureContext: ~
67
coverage:
78
extensions:
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
namespace Tests\Functional\BehatContext;
3+
4+
use Behat\Behat\Context\Context;
5+
6+
class AbstractContext implements Context
7+
{
8+
public function jsonDecode($encodedData)
9+
{
10+
$decoded = json_decode($encodedData, true);
11+
12+
if (JSON_ERROR_NONE != json_last_error()) {
13+
throw new \Exception(
14+
json_last_error_msg(),
15+
json_last_error()
16+
);
17+
}
18+
19+
return $decoded;
20+
}
21+
}

features/bootstrap/FeatureContext.php

Lines changed: 28 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,58 @@
11
<?php
22
namespace Tests\Functional\BehatContext;
33

4-
use Behat\Behat\Context\Context;
54
use Behat\Gherkin\Node\PyStringNode;
65
use PHPUnit\Framework\Assert;
7-
use PHPUnit\Framework\Constraint\IsIdentical;
8-
use Symfony\Component\Validator\ValidatorBuilder;
9-
use Yoanm\JsonRpcParamsSymfonyValidator\Infra\JsonRpcParamsValidator;
10-
use Yoanm\JsonRpcServer\Domain\Model\JsonRpcRequest;
6+
use Tests\Functional\BehatContext\Helper\FakeEndpointCreator;
117

128
/**
139
* Defines application features from the specific context.
1410
*/
15-
class FeatureContext implements Context
11+
class FeatureContext extends AbstractContext
1612
{
17-
/** @var array */
18-
private $lastViolationList = [];
13+
const KEY_JSON_RPC = 'jsonrpc';
14+
const KEY_ID = 'id';
15+
const KEY_ERROR = 'error';
1916

20-
/**
21-
* @When I validate method :methodClass with:
22-
*/
23-
public function whenIValidateMethodWith($methodClass, PyStringNode $payload)
24-
{
25-
$jsonRpcRequest = new JsonRpcRequest('2.0', $methodClass);
26-
$jsonRpcRequest->setParamList(json_decode($payload->getRaw(), true));
17+
const SUB_KEY_ERROR_CODE = 'code';
18+
const SUB_KEY_ERROR_MESSAGE = 'message';
2719

28-
$this->lastViolationList = $this->getValidator()->validate($jsonRpcRequest, new $methodClass);
29-
}
20+
/** @var string|null */
21+
private $lastResponse = null;
3022

3123
/**
32-
* @Then I should have no violation
24+
* @When I send following payload:
3325
*/
34-
public function thenIShouldHaveNoViolation()
26+
public function whenISendTheFollowingPayload(PyStringNode $payload)
3527
{
36-
Assert::assertEmpty($this->lastViolationList);
28+
$endpoint = (new FakeEndpointCreator())->create();
29+
30+
$this->lastResponse = $endpoint->index($payload->getRaw());
3731
}
3832

3933
/**
40-
* @Then I should have 1 violation
41-
* @Then I should have :count violations
34+
* @Then I should have the following response:
4235
*/
43-
public function thenIShouldHaveXViolation($count = 1)
36+
public function thenIShouldHaveTheFollowingResponse(PyStringNode $expectedResult)
4437
{
45-
Assert::assertCount((int) $count, $this->lastViolationList);
38+
// Decode content to get rid of any indentation/spacing/... issues
39+
Assert::assertEquals(
40+
$this->jsonDecode($expectedResult->getRaw()),
41+
$this->getLastResponseDecoded()
42+
);
4643
}
4744

4845
/**
49-
* @Then I should have the following validation error:
46+
* @Then I should have an empty response
5047
*/
51-
public function thenIShouldHaveTheFollowingViolation(PyStringNode $node)
48+
public function thenIShouldHaveAnEmptyResponse()
5249
{
53-
$found = false;
54-
$decoded = json_decode($node->getRaw(), true);
55-
$constraint = new IsIdentical($decoded);
56-
foreach ($this->lastViolationList as $violation) {
57-
if (true === $constraint->evaluate($violation, '', true)) {
58-
$found = true;
59-
break;
60-
}
61-
}
62-
63-
if (true !== $found) {
64-
throw new \Exception(
65-
sprintf(
66-
'Violation "%s" not found in violation list : %s',
67-
json_encode($decoded),
68-
json_encode($this->lastViolationList)
69-
)
70-
);
71-
}
50+
// Decode content to get rid of any indentation/spacing/... issues
51+
Assert::assertEmpty($this->getLastResponseDecoded());
7252
}
73-
/**
74-
* @return JsonRpcParamsValidator
75-
*/
76-
private function getValidator() : JsonRpcParamsValidator
53+
54+
private function getLastResponseDecoded()
7755
{
78-
return new JsonRpcParamsValidator(
79-
(new ValidatorBuilder())->getValidator()
80-
);
56+
return $this->jsonDecode($this->lastResponse);
8157
}
8258
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
namespace Tests\Functional\BehatContext\Helper;
3+
4+
use DemoApp\Method\BasicMethod;
5+
use DemoApp\Method\BasicMethodWithRequiredParams;
6+
use DemoApp\Resolver\JsonRpcMethodResolver;
7+
use Symfony\Component\Validator\ValidatorBuilder;
8+
use Tests\Functional\BehatContext\App\Method\AbstractMethod;
9+
use Yoanm\JsonRpcParamsSymfonyValidator\Infra\JsonRpcParamsValidator;
10+
use Yoanm\JsonRpcServer\App\Creator\ResponseCreator;
11+
use Yoanm\JsonRpcServer\App\Handler\ExceptionHandler;
12+
use Yoanm\JsonRpcServer\App\Handler\JsonRpcRequestHandler;
13+
use Yoanm\JsonRpcServer\App\Serialization\JsonRpcCallDenormalizer;
14+
use Yoanm\JsonRpcServer\App\Serialization\JsonRpcCallResponseNormalizer;
15+
use Yoanm\JsonRpcServer\App\Serialization\JsonRpcCallSerializer;
16+
use Yoanm\JsonRpcServer\App\Serialization\JsonRpcRequestDenormalizer;
17+
use Yoanm\JsonRpcServer\App\Serialization\JsonRpcResponseNormalizer;
18+
use Yoanm\JsonRpcServer\Infra\Endpoint\JsonRpcEndpoint;
19+
20+
class FakeEndpointCreator
21+
{
22+
/**
23+
* @return JsonRpcEndpoint
24+
*/
25+
public function create() : JsonRpcEndpoint
26+
{
27+
/** @var AbstractMethod[] $methodList */
28+
$methodList = [
29+
'basic-method' => new BasicMethod(),
30+
'basic-method-with-params' => new BasicMethodWithRequiredParams(),
31+
];
32+
33+
$methodResolver = new JsonRpcMethodResolver();
34+
35+
foreach ($methodList as $methodName => $method) {
36+
$methodResolver->addJsonRpcMethod($methodName, $method);
37+
}
38+
39+
$jsonRpcSerializer = new JsonRpcCallSerializer(
40+
new JsonRpcCallDenormalizer(
41+
new JsonRpcRequestDenormalizer()
42+
),
43+
new JsonRpcCallResponseNormalizer(
44+
new JsonRpcResponseNormalizer()
45+
)
46+
);
47+
$responseCreator = new ResponseCreator();
48+
$requestHandler = new JsonRpcRequestHandler($methodResolver, $responseCreator);
49+
$exceptionHandler = new ExceptionHandler($responseCreator);
50+
$endpoint = new JsonRpcEndpoint($jsonRpcSerializer, $requestHandler, $exceptionHandler);
51+
$requestHandler->setMethodParamsValidator(
52+
new JsonRpcParamsValidator(
53+
(new ValidatorBuilder())->getValidator()
54+
)
55+
);
56+
57+
return $endpoint;
58+
}
59+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<?php
2+
namespace Tests\Functional\BehatContext;
3+
4+
use Behat\Behat\Context\Context;
5+
use Behat\Gherkin\Node\PyStringNode;
6+
use PHPUnit\Framework\Assert;
7+
use PHPUnit\Framework\Constraint\IsIdentical;
8+
use Symfony\Component\Validator\ValidatorBuilder;
9+
use Yoanm\JsonRpcParamsSymfonyValidator\Infra\JsonRpcParamsValidator;
10+
use Yoanm\JsonRpcServer\Domain\Model\JsonRpcRequest;
11+
12+
/**
13+
* Defines application features from the specific context.
14+
*/
15+
class StandaloneContext implements Context
16+
{
17+
/** @var array */
18+
private $lastViolationList = [];
19+
20+
/**
21+
* @When I validate method :methodClass with:
22+
*/
23+
public function whenIValidateMethodWith($methodClass, PyStringNode $payload)
24+
{
25+
$jsonRpcRequest = new JsonRpcRequest('2.0', $methodClass);
26+
$jsonRpcRequest->setParamList(json_decode($payload->getRaw(), true));
27+
28+
$this->lastViolationList = $this->getValidator()->validate($jsonRpcRequest, new $methodClass);
29+
}
30+
31+
/**
32+
* @Then I should have no violation
33+
*/
34+
public function thenIShouldHaveNoViolation()
35+
{
36+
Assert::assertEmpty($this->lastViolationList);
37+
}
38+
39+
/**
40+
* @Then I should have 1 violation
41+
* @Then I should have :count violations
42+
*/
43+
public function thenIShouldHaveXViolation($count = 1)
44+
{
45+
Assert::assertCount((int) $count, $this->lastViolationList);
46+
}
47+
48+
/**
49+
* @Then I should have the following validation error:
50+
*/
51+
public function thenIShouldHaveTheFollowingViolation(PyStringNode $node)
52+
{
53+
$found = false;
54+
$decoded = json_decode($node->getRaw(), true);
55+
$constraint = new IsIdentical($decoded);
56+
foreach ($this->lastViolationList as $violation) {
57+
if (true === $constraint->evaluate($violation, '', true)) {
58+
$found = true;
59+
break;
60+
}
61+
}
62+
63+
if (true !== $found) {
64+
throw new \Exception(
65+
sprintf(
66+
'Violation "%s" not found in violation list : %s',
67+
json_encode($decoded),
68+
json_encode($this->lastViolationList)
69+
)
70+
);
71+
}
72+
}
73+
/**
74+
* @return JsonRpcParamsValidator
75+
*/
76+
private function getValidator() : JsonRpcParamsValidator
77+
{
78+
return new JsonRpcParamsValidator(
79+
(new ValidatorBuilder())->getValidator()
80+
);
81+
}
82+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
namespace DemoApp\Resolver;
3+
4+
use Yoanm\JsonRpcServer\Domain\JsonRpcMethodAwareInterface;
5+
use Yoanm\JsonRpcServer\Domain\JsonRpcMethodInterface;
6+
use Yoanm\JsonRpcServer\Domain\JsonRpcMethodResolverInterface as BasResolverInterface;
7+
8+
class JsonRpcMethodResolver implements BasResolverInterface, JsonRpcMethodAwareInterface
9+
{
10+
/** @var JsonRpcMethodInterface[] */
11+
private $methodList;
12+
13+
/**
14+
* {@inheritdoc}
15+
*/
16+
public function resolve(string $methodName) : ?JsonRpcMethodInterface
17+
{
18+
if (!array_key_exists($methodName, $this->methodList)) {
19+
return null;
20+
}
21+
22+
return $this->methodList[$methodName];
23+
}
24+
25+
/**
26+
* @param JsonRpcMethodInterface $method
27+
* @param string $methodName
28+
*/
29+
public function addJsonRpcMethod(string $methodName, JsonRpcMethodInterface $method) : void
30+
{
31+
$this->methodList[$methodName] = $method;
32+
}
33+
}

features/json-rpc_server.feature

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
Feature: Validator
2+
3+
Scenario: Validator should do nothing for method which does not implement right interface
4+
When I send following payload:
5+
"""
6+
{"jsonrpc": "2.0", "method": "basic-method", "id": 1}
7+
"""
8+
Then I should have the following response:
9+
"""
10+
{"jsonrpc":"2.0", "result":"basic-method-result", "id":1}
11+
"""
12+
13+
Scenario: Validator should return an empty list if there is no violations
14+
When I send following payload:
15+
"""
16+
{
17+
"jsonrpc": "2.0",
18+
"method": "basic-method-with-params",
19+
"params": {
20+
"fieldA": "plop",
21+
"fieldB": "plip"
22+
},
23+
"id": 1
24+
}
25+
"""
26+
Then I should have the following response:
27+
"""
28+
{"jsonrpc":"2.0", "result":"basic-method-with-params-result", "id":1}
29+
"""
30+
31+
Scenario: Validator should return list of violations if there is some
32+
When I send following payload:
33+
"""
34+
{
35+
"jsonrpc": "2.0",
36+
"method": "basic-method-with-params",
37+
"params": {
38+
"fieldA": null,
39+
"fieldB": ""
40+
},
41+
"id": 1
42+
}
43+
"""
44+
Then I should have the following response:
45+
"""
46+
{
47+
"jsonrpc":"2.0",
48+
"error": {
49+
"code": -32602,
50+
"message": "Invalid params",
51+
"data": {
52+
"violations": [
53+
{
54+
"path": "[fieldA]",
55+
"message": "This value should not be null.",
56+
"code": "ad32d13f-c3d4-423b-909a-857b961eb720"
57+
},
58+
{
59+
"path": "[fieldB]",
60+
"message": "This value should not be blank.",
61+
"code":"c1051bb4-d103-4f74-8988-acbcafc7fdc3"
62+
}
63+
]
64+
}
65+
},
66+
"id":1
67+
}
68+
"""
File renamed without changes.

0 commit comments

Comments
 (0)