2017-07-16 14:52:38 +03:00
< ? php
namespace GraphQL\Tests\Server ;
2017-07-19 15:30:39 +03:00
use GraphQL\Error\Error ;
2017-07-17 12:57:30 +03:00
use GraphQL\Error\InvariantViolation ;
2017-07-16 14:52:38 +03:00
use GraphQL\Server\Helper ;
use GraphQL\Server\OperationParams ;
2017-08-07 22:00:17 +03:00
use GraphQL\Server\RequestError ;
2017-08-15 16:45:23 +03:00
use GraphQL\Tests\Server\Psr7\PsrRequestStub ;
use GraphQL\Tests\Server\Psr7\PsrStreamStub ;
2017-07-16 14:52:38 +03:00
class RequestParsingTest extends \PHPUnit_Framework_TestCase
{
2017-07-17 12:57:30 +03:00
public function testParsesGraphqlRequest ()
2017-07-16 14:52:38 +03:00
{
$query = '{my query}' ;
2017-08-15 16:45:23 +03:00
$parsed = [
'raw' => $this -> parseRawRequest ( 'application/graphql' , $query ),
'psr' => $this -> parsePsrRequest ( 'application/graphql' , $query )
];
2017-07-16 14:52:38 +03:00
2017-08-15 16:45:23 +03:00
foreach ( $parsed as $source => $parsedBody ) {
$this -> assertValidOperationParams ( $parsedBody , $query , null , null , null , $source );
$this -> assertFalse ( $parsedBody -> isReadOnly (), $source );
}
2017-07-16 14:52:38 +03:00
}
2017-07-17 12:57:30 +03:00
public function testParsesUrlencodedRequest ()
2017-07-16 14:52:38 +03:00
{
$query = '{my query}' ;
$variables = [ 'test' => 1 , 'test2' => 2 ];
$operation = 'op' ;
$post = [
'query' => $query ,
'variables' => $variables ,
'operation' => $operation
];
2017-08-15 16:45:23 +03:00
$parsed = [
'raw' => $this -> parseRawFormUrlencodedRequest ( $post ),
'psr' => $this -> parsePsrFormUrlEncodedRequest ( $post )
];
2017-07-16 14:52:38 +03:00
2017-08-15 16:45:23 +03:00
foreach ( $parsed as $method => $parsedBody ) {
$this -> assertValidOperationParams ( $parsedBody , $query , null , $variables , $operation , $method );
$this -> assertFalse ( $parsedBody -> isReadOnly (), $method );
}
2017-07-16 14:52:38 +03:00
}
2017-07-17 12:57:30 +03:00
public function testParsesGetRequest ()
2017-07-16 14:52:38 +03:00
{
$query = '{my query}' ;
$variables = [ 'test' => 1 , 'test2' => 2 ];
$operation = 'op' ;
$get = [
'query' => $query ,
'variables' => $variables ,
'operation' => $operation
];
2017-08-15 16:45:23 +03:00
$parsed = [
'raw' => $this -> parseRawGetRequest ( $get ),
'psr' => $this -> parsePsrGetRequest ( $get )
];
2017-07-16 14:52:38 +03:00
2017-08-15 16:45:23 +03:00
foreach ( $parsed as $method => $parsedBody ) {
$this -> assertValidOperationParams ( $parsedBody , $query , null , $variables , $operation , $method );
$this -> assertTrue ( $parsedBody -> isReadonly (), $method );
}
2017-07-16 14:52:38 +03:00
}
2017-07-17 12:57:30 +03:00
public function testParsesJSONRequest ()
2017-07-16 14:52:38 +03:00
{
$query = '{my query}' ;
$variables = [ 'test' => 1 , 'test2' => 2 ];
$operation = 'op' ;
$body = [
'query' => $query ,
'variables' => $variables ,
'operation' => $operation
];
2017-08-15 16:45:23 +03:00
$parsed = [
'raw' => $this -> parseRawRequest ( 'application/json' , json_encode ( $body )),
'psr' => $this -> parsePsrRequest ( 'application/json' , json_encode ( $body ))
];
foreach ( $parsed as $method => $parsedBody ) {
$this -> assertValidOperationParams ( $parsedBody , $query , null , $variables , $operation , $method );
$this -> assertFalse ( $parsedBody -> isReadOnly (), $method );
}
2017-07-16 14:52:38 +03:00
}
2017-07-19 15:30:39 +03:00
public function testParsesVariablesAsJSON ()
{
$query = '{my query}' ;
$variables = [ 'test' => 1 , 'test2' => 2 ];
$operation = 'op' ;
$body = [
'query' => $query ,
'variables' => json_encode ( $variables ),
'operation' => $operation
];
2017-08-15 16:45:23 +03:00
$parsed = [
'raw' => $this -> parseRawRequest ( 'application/json' , json_encode ( $body )),
'psr' => $this -> parsePsrRequest ( 'application/json' , json_encode ( $body ))
];
foreach ( $parsed as $method => $parsedBody ) {
$this -> assertValidOperationParams ( $parsedBody , $query , null , $variables , $operation , $method );
$this -> assertFalse ( $parsedBody -> isReadOnly (), $method );
}
2017-07-19 15:30:39 +03:00
}
public function testIgnoresInvalidVariablesJson ()
{
$query = '{my query}' ;
$variables = '"some invalid json' ;
$operation = 'op' ;
$body = [
'query' => $query ,
'variables' => $variables ,
'operation' => $operation
];
2017-08-15 16:45:23 +03:00
$parsed = [
'raw' => $this -> parseRawRequest ( 'application/json' , json_encode ( $body )),
'psr' => $this -> parsePsrRequest ( 'application/json' , json_encode ( $body )),
];
foreach ( $parsed as $method => $parsedBody ) {
$this -> assertValidOperationParams ( $parsedBody , $query , null , $variables , $operation , $method );
$this -> assertFalse ( $parsedBody -> isReadOnly (), $method );
}
2017-07-19 15:30:39 +03:00
}
2017-07-16 14:52:38 +03:00
public function testParsesBatchJSONRequest ()
{
$body = [
[
'query' => '{my query}' ,
'variables' => [ 'test' => 1 , 'test2' => 2 ],
'operation' => 'op'
],
[
'queryId' => 'my-query-id' ,
'variables' => [ 'test' => 1 , 'test2' => 2 ],
'operation' => 'op2'
],
];
2017-08-15 16:45:23 +03:00
$parsed = [
'raw' => $this -> parseRawRequest ( 'application/json' , json_encode ( $body )),
'psr' => $this -> parsePsrRequest ( 'application/json' , json_encode ( $body ))
];
foreach ( $parsed as $method => $parsedBody ) {
$this -> assertInternalType ( 'array' , $parsedBody , $method );
$this -> assertCount ( 2 , $parsedBody , $method );
$this -> assertValidOperationParams ( $parsedBody [ 0 ], $body [ 0 ][ 'query' ], null , $body [ 0 ][ 'variables' ], $body [ 0 ][ 'operation' ], $method );
$this -> assertValidOperationParams ( $parsedBody [ 1 ], null , $body [ 1 ][ 'queryId' ], $body [ 1 ][ 'variables' ], $body [ 1 ][ 'operation' ], $method );
}
2017-07-16 14:52:38 +03:00
}
2017-12-21 09:52:43 +03:00
public function testFailsParsingInvalidRawJsonRequestRaw ()
2017-07-16 14:52:38 +03:00
{
$body = 'not really{} a json' ;
2017-12-21 09:52:43 +03:00
$this -> setExpectedException ( RequestError :: class , 'Could not parse JSON: Syntax error' );
2017-08-15 16:45:23 +03:00
$this -> parseRawRequest ( 'application/json' , $body );
}
2017-12-21 09:52:43 +03:00
public function testFailsParsingInvalidRawJsonRequestPsr ()
{
$body = 'not really{} a json' ;
$this -> setExpectedException ( InvariantViolation :: class , 'PSR-7 request is expected to provide parsed body for "application/json" requests but got null' );
2017-08-15 16:45:23 +03:00
$this -> parsePsrRequest ( 'application/json' , $body );
2017-07-16 14:52:38 +03:00
}
2017-12-21 09:01:57 +03:00
public function testFailsParsingNonPreParsedPsrRequest ()
{
try {
2018-01-13 14:08:07 +03:00
$this -> parsePsrRequest ( 'application/json' , json_encode ( null ));
2017-12-21 09:01:57 +03:00
$this -> fail ( 'Expected exception not thrown' );
} catch ( InvariantViolation $e ) {
// Expecting parsing exception to be thrown somewhere else:
$this -> assertEquals (
2018-01-13 14:08:07 +03:00
'PSR-7 request is expected to provide parsed body for "application/json" requests but got null' ,
2017-12-21 09:01:57 +03:00
$e -> getMessage ()
);
}
}
2017-08-15 16:45:23 +03:00
// There is no equivalent for psr request, because it should throw
2017-12-21 09:52:43 +03:00
public function testFailsParsingNonArrayOrObjectJsonRequestRaw ()
2017-07-16 14:52:38 +03:00
{
$body = '"str"' ;
2017-12-21 09:52:43 +03:00
$this -> setExpectedException ( RequestError :: class , 'GraphQL Server expects JSON object or array, but got "str"' );
2017-08-15 16:45:23 +03:00
$this -> parseRawRequest ( 'application/json' , $body );
}
2017-12-21 09:52:43 +03:00
public function testFailsParsingNonArrayOrObjectJsonRequestPsr ()
{
$body = '"str"' ;
$this -> setExpectedException ( RequestError :: class , 'GraphQL Server expects JSON object or array, but got "str"' );
2017-08-15 16:45:23 +03:00
$this -> parsePsrRequest ( 'application/json' , $body );
}
2017-12-21 09:52:43 +03:00
public function testFailsParsingInvalidContentTypeRaw ()
{
$contentType = 'not-supported-content-type' ;
$body = 'test' ;
$this -> setExpectedException ( RequestError :: class , 'Unexpected content type: "not-supported-content-type"' );
$this -> parseRawRequest ( $contentType , $body );
2017-07-16 14:52:38 +03:00
}
2017-12-21 09:52:43 +03:00
public function testFailsParsingInvalidContentTypePsr ()
2017-07-16 14:52:38 +03:00
{
2017-08-15 16:45:23 +03:00
$contentType = 'not-supported-content-type' ;
$body = 'test' ;
2017-12-21 09:52:43 +03:00
$this -> setExpectedException ( RequestError :: class , 'Unexpected content type: "not-supported-content-type"' );
2017-08-15 16:45:23 +03:00
$this -> parseRawRequest ( $contentType , $body );
}
2017-07-16 14:52:38 +03:00
2017-12-21 09:52:43 +03:00
public function testFailsWithMissingContentTypeRaw ()
2017-07-16 14:52:38 +03:00
{
2017-12-21 09:52:43 +03:00
$this -> setExpectedException ( RequestError :: class , 'Missing "Content-Type" header' );
2017-08-15 16:45:23 +03:00
$this -> parseRawRequest ( null , 'test' );
}
2017-12-21 09:52:43 +03:00
public function testFailsWithMissingContentTypePsr ()
{
$this -> setExpectedException ( RequestError :: class , 'Missing "Content-Type" header' );
2017-08-15 16:45:23 +03:00
$this -> parsePsrRequest ( null , 'test' );
2017-07-16 14:52:38 +03:00
}
2017-12-21 09:52:43 +03:00
public function testFailsOnMethodsOtherThanPostOrGetRaw ()
2017-07-16 14:52:38 +03:00
{
2017-12-21 09:52:43 +03:00
$this -> setExpectedException ( RequestError :: class , 'HTTP Method "PUT" is not supported' );
2018-01-13 13:20:00 +03:00
$this -> parseRawRequest ( 'application/json' , json_encode ([]), " PUT " );
}
2017-08-15 16:45:23 +03:00
2017-12-21 09:52:43 +03:00
public function testFailsOnMethodsOtherThanPostOrGetPsr ()
{
$this -> setExpectedException ( RequestError :: class , 'HTTP Method "PUT" is not supported' );
2018-01-13 13:20:00 +03:00
$this -> parsePsrRequest ( 'application/json' , json_encode ([]), " PUT " );
2017-07-16 14:52:38 +03:00
}
/**
* @ param string $contentType
* @ param string $content
* @ param $method
*
* @ return OperationParams | OperationParams []
*/
private function parseRawRequest ( $contentType , $content , $method = 'POST' )
{
$_SERVER [ 'CONTENT_TYPE' ] = $contentType ;
$_SERVER [ 'REQUEST_METHOD' ] = $method ;
$helper = new Helper ();
2017-07-17 12:57:30 +03:00
return $helper -> parseHttpRequest ( function () use ( $content ) {
2017-07-16 14:52:38 +03:00
return $content ;
});
}
2017-08-15 16:45:23 +03:00
/**
* @ param string $contentType
* @ param string $content
* @ param $method
*
* @ return OperationParams | OperationParams []
*/
private function parsePsrRequest ( $contentType , $content , $method = 'POST' )
{
$psrRequestBody = new PsrStreamStub ();
$psrRequestBody -> content = $content ;
$psrRequest = new PsrRequestStub ();
$psrRequest -> headers [ 'content-type' ] = [ $contentType ];
$psrRequest -> method = $method ;
$psrRequest -> body = $psrRequestBody ;
if ( $contentType === 'application/json' ) {
$parsedBody = json_decode ( $content , true );
$parsedBody = $parsedBody === false ? null : $parsedBody ;
} else {
$parsedBody = null ;
}
$psrRequest -> parsedBody = $parsedBody ;
$helper = new Helper ();
return $helper -> parsePsrRequest ( $psrRequest );
}
2017-07-16 14:52:38 +03:00
/**
* @ param array $postValue
* @ return OperationParams | OperationParams []
*/
2017-08-15 16:45:23 +03:00
private function parseRawFormUrlencodedRequest ( $postValue )
2017-07-16 14:52:38 +03:00
{
$_SERVER [ 'CONTENT_TYPE' ] = 'application/x-www-form-urlencoded' ;
$_SERVER [ 'REQUEST_METHOD' ] = 'POST' ;
$_POST = $postValue ;
$helper = new Helper ();
2017-07-17 12:57:30 +03:00
return $helper -> parseHttpRequest ( function () {
throw new InvariantViolation ( " Shouldn't read from php://input for urlencoded request " );
});
2017-07-16 14:52:38 +03:00
}
2017-08-15 16:45:23 +03:00
/**
* @ param $postValue
* @ return array | Helper
*/
private function parsePsrFormUrlEncodedRequest ( $postValue )
{
$psrRequest = new PsrRequestStub ();
$psrRequest -> headers [ 'content-type' ] = [ 'application/x-www-form-urlencoded' ];
$psrRequest -> method = 'POST' ;
$psrRequest -> parsedBody = $postValue ;
$helper = new Helper ();
return $helper -> parsePsrRequest ( $psrRequest );
}
2017-07-16 14:52:38 +03:00
/**
* @ param $getValue
2017-07-17 12:57:30 +03:00
* @ return OperationParams
2017-07-16 14:52:38 +03:00
*/
2017-08-15 16:45:23 +03:00
private function parseRawGetRequest ( $getValue )
2017-07-16 14:52:38 +03:00
{
$_SERVER [ 'REQUEST_METHOD' ] = 'GET' ;
$_GET = $getValue ;
$helper = new Helper ();
2017-07-17 12:57:30 +03:00
return $helper -> parseHttpRequest ( function () {
throw new InvariantViolation ( " Shouldn't read from php://input for urlencoded request " );
});
2017-07-16 14:52:38 +03:00
}
2017-08-15 16:45:23 +03:00
/**
* @ param $getValue
* @ return array | Helper
*/
private function parsePsrGetRequest ( $getValue )
{
$psrRequest = new PsrRequestStub ();
$psrRequest -> method = 'GET' ;
$psrRequest -> queryParams = $getValue ;
$helper = new Helper ();
return $helper -> parsePsrRequest ( $psrRequest );
}
2017-07-16 14:52:38 +03:00
/**
* @ param OperationParams $params
* @ param string $query
* @ param string $queryId
* @ param array $variables
* @ param string $operation
*/
2017-08-15 16:45:23 +03:00
private function assertValidOperationParams ( $params , $query , $queryId = null , $variables = null , $operation = null , $message = '' )
2017-07-16 14:52:38 +03:00
{
2017-08-15 16:45:23 +03:00
$this -> assertInstanceOf ( OperationParams :: class , $params , $message );
2017-07-16 14:52:38 +03:00
2017-08-15 16:45:23 +03:00
$this -> assertSame ( $query , $params -> query , $message );
$this -> assertSame ( $queryId , $params -> queryId , $message );
$this -> assertSame ( $variables , $params -> variables , $message );
$this -> assertSame ( $operation , $params -> operation , $message );
2017-07-16 14:52:38 +03:00
}
}