22namespace Tests \Functional \BehatContext ;
33
44use Behat \Behat \Context \Context ;
5+ use Behat \Gherkin \Node \PyStringNode ;
6+ use Behat \Gherkin \Node \TableNode ;
7+ use PHPUnit \Framework \Assert ;
8+ use Prophecy \Argument ;
9+ use Prophecy \Prophet ;
10+ use Symfony \Component \DependencyInjection \ContainerBuilder ;
11+ use Symfony \Component \DependencyInjection \Definition ;
12+ use Symfony \Component \HttpFoundation \Request ;
13+ use Tests \Functional \BehatContext \App \CustomMethodResolver ;
14+ use Tests \Functional \BehatContext \App \JsonRpcMethod ;
15+ use Yoanm \JsonRpcServer \Infra \Endpoint \JsonRpcEndpoint ;
16+ use Yoanm \SymfonyJsonRpcHttpServer \Infra \Endpoint \JsonRpcHttpEndpoint ;
17+ use Yoanm \SymfonyJsonRpcHttpServer \Infra \Symfony \DependencyInjection \JsonRpcHttpServerExtension ;
518
619/**
720 * Defines application features from the specific context.
821 */
922class FeatureContext implements Context
1023{
24+ const CUSTOM_METHOD_RESOLVER_SERVICE_ID = 'custom-method-resolver-service ' ;
25+
26+ /** @var JsonRpcHttpServerExtension */
27+ private $ extension ;
28+ /** @var Prophet */
29+ private $ prophet ;
30+ /** @var ContainerBuilder */
31+ private $ containerBuilder ;
32+ /** @var mixed */
33+ private $ endpoint ;
1134 /**
1235 * Initializes context.
1336 *
@@ -17,5 +40,190 @@ class FeatureContext implements Context
1740 */
1841 public function __construct ()
1942 {
43+ $ this ->prophet = new Prophet ();
44+ }
45+
46+ /**
47+ * @Given I process the symfony extension
48+ */
49+ public function givenIProcessTheSymfonyExtension ()
50+ {
51+ (new JsonRpcHttpServerExtension ())->load ([], $ this ->getContainerBuilder ());
52+ }
53+
54+ /**
55+ * @Given there is a public :serviceName JSON-RPC method service
56+ */
57+ public function givenThereAJsonRpcMethodService ($ serviceId )
58+ {
59+ $ this ->getContainerBuilder ()->setDefinition ($ serviceId , $ this ->createJsonRpcMethodDefinition ());
60+ }
61+
62+ /**
63+ * @Given I inject my :methodName to :serviceName JSON-RPC mapping into default method resolver definition
64+ */
65+ public function givenIInjectMyJsonRpcMethodIntoDefaultMethodResolverDefinition ($ methodName , $ serviceName )
66+ {
67+ $ this ->injectJsonRpcMethodToDefaultResolverService ($ methodName , $ serviceName , true );
68+ }
69+
70+ /**
71+ * @Given I inject my :methodName to :serviceName JSON-RPC mapping into default method resolver instance
72+ */
73+ public function givenIInjectMyJsonRpcMethodIntoDefaultMethodResolverInstance ($ methodName , $ serviceName )
74+ {
75+ $ this ->injectJsonRpcMethodToDefaultResolverService ($ methodName , $ serviceName );
76+ }
77+
78+ /**
79+ * @Given I tag my custom method resolver service with :tagName
80+ */
81+ public function givenITagMyCustomMethodResolverServiceWith ($ tagName )
82+ {
83+ $ this ->getContainerBuilder ()->findDefinition (self ::CUSTOM_METHOD_RESOLVER_SERVICE_ID )->addTag ($ tagName );
84+ }
85+
86+ /**
87+ * @Given I inject my :methodName JSON-RPC method into my custom method resolver instance
88+ */
89+ public function givenIInjectMyJsonRpcMethodIntoMyCustomMethodResolverInstance ($ methodName )
90+ {
91+ $ this ->injectJsonRpcMethodToCustomResolverService ($ methodName , $ this ->createJsonRpcMethod ());
92+ }
93+
94+ /**
95+ * @Given I inject my :methodName JSON-RPC method into my custom method resolver definition
96+ */
97+ public function givenIInjectMyJsonRpcMethodIntoMyCustomMethodResolverDefinition ($ methodName )
98+ {
99+ $ this ->injectJsonRpcMethodToCustomResolverService ($ methodName , $ this ->createJsonRpcMethodDefinition ());
100+ }
101+
102+ /**
103+ * @Given I have a JSON-RPC method service definition with :tagName tag and following tag attributes:
104+ */
105+ public function givenITagMyJsonRpcMethodServiceWithTagAndFollowingAttributes (
106+ $ tagName ,
107+ PyStringNode $ tagAttributeNode
108+ ) {
109+ $ definition = $ this ->createJsonRpcMethodDefinition ()
110+ ->addTag ($ tagName , json_decode ($ tagAttributeNode , true ));
111+ $ this ->getContainerBuilder ()->setDefinition (uniqid (), $ definition );
112+ }
113+
114+ /**
115+ * @When I load endpoint from :serviceId service
116+ */
117+ public function whenILoadEndpointFromService ($ serviceId )
118+ {
119+ $ this ->getContainerBuilder ()->compile ();
120+ $ this ->endpoint = $ this ->getContainerBuilder ()->get ($ serviceId );
121+ }
122+
123+ /**
124+ * @Then endpoint should respond to following JSON-RPC methods:
125+ */
126+ public function thenEndpointShouldResponseToFollowingJsonRpcMethods (TableNode $ methodList )
127+ {
128+ Assert::assertInstanceOf (JsonRpcHttpEndpoint::class, $ this ->endpoint );
129+ $ methodList = array_map ('array_shift ' , $ methodList ->getRows ());
130+ $ this ->assertEndpointRespondToCalls ($ this ->endpoint , $ methodList );
131+ }
132+
133+ /**
134+ * @param JsonRpcEndpoint $endpoint
135+ * @param array $methodNameList
136+ */
137+ private function assertEndpointRespondToCalls (JsonRpcHttpEndpoint $ endpoint , array $ methodNameList )
138+ {
139+ foreach ($ methodNameList as $ methodName ) {
140+ $ requestId = uniqid ();
141+ $ requestContent = json_encode (
142+ [
143+ 'jsonrpc ' => '2.0 ' ,
144+ 'id ' => $ requestId ,
145+ 'method ' => $ methodName
146+ ]
147+ );
148+ $ request = new Request ([], [], [], [], [], [], $ requestContent );
149+ $ request ->setMethod (Request::METHOD_POST );
150+ Assert::assertSame (
151+ json_encode (
152+ [
153+ 'jsonrpc ' => '2.0 ' ,
154+ 'id ' => $ requestId ,
155+ 'result ' => 'OK '
156+ ]
157+ ),
158+ $ endpoint ->index ($ request )->getContent ()
159+ );
160+ }
161+ }
162+
163+ /**
164+ * @return JsonRpcMethod
165+ */
166+ private function createJsonRpcMethod ()
167+ {
168+ return new JsonRpcMethod ();
169+ }
170+
171+ /**
172+ * @return Definition
173+ */
174+ private function createJsonRpcMethodDefinition ()
175+ {
176+ return (new Definition (JsonRpcMethod::class))->setPrivate (false );
177+ }
178+
179+ /**
180+ * @param string $methodName
181+ * @param string $methodServiceId
182+ * @param bool|false $isDefinition
183+ */
184+ private function injectJsonRpcMethodToDefaultResolverService ($ methodName , $ methodServiceId , $ isDefinition = false )
185+ {
186+ $ resolverServiceId = JsonRpcHttpServerExtension::SERVICE_NAME_RESOLVER_SERVICE_NAME ;
187+ if (true === $ isDefinition ) {
188+ $ this ->getContainerBuilder ()
189+ ->getDefinition ($ resolverServiceId )
190+ ->addMethodCall ('addMethodMapping ' , [$ methodName , $ methodServiceId ]);
191+ } else {
192+ $ this ->getContainerBuilder ()
193+ ->get ($ resolverServiceId )
194+ ->addMethodMapping ($ methodName , $ methodServiceId );
195+ }
196+ }
197+
198+ /**
199+ * @param string $methodName
200+ * @param JsonRpcMethod|Definition $method
201+ */
202+ private function injectJsonRpcMethodToCustomResolverService ($ methodName , $ method )
203+ {
204+ $ resolverServiceId = self ::CUSTOM_METHOD_RESOLVER_SERVICE_ID ;
205+ if ($ method instanceof Definition) {
206+ $ this ->getContainerBuilder ()
207+ ->getDefinition ($ resolverServiceId )
208+ ->addMethodCall ('addMethod ' , [$ method , $ methodName ]);
209+ } else {
210+ $ this ->getContainerBuilder ()
211+ ->get ($ resolverServiceId )
212+ ->addMethod ($ method , $ methodName );
213+ }
214+ }
215+
216+ /**
217+ * @return ContainerBuilder
218+ */
219+ private function getContainerBuilder ()
220+ {
221+ if (!$ this ->containerBuilder ) {
222+ $ this ->containerBuilder = new ContainerBuilder ();
223+ // Add definition of custom resolver (without tags)
224+ $ customResolverDefinition = (new Definition (CustomMethodResolver::class))->setPrivate (false );
225+ $ this ->containerBuilder ->setDefinition (self ::CUSTOM_METHOD_RESOLVER_SERVICE_ID , $ customResolverDefinition );
226+ }
227+ return $ this ->containerBuilder ;
20228 }
21229}
0 commit comments