Merge pull request #340 from simPod/cs-language-server

Fix CS in tests/Server
This commit is contained in:
Vladimir Razuvaev 2018-09-02 21:23:47 +07:00 committed by GitHub
commit ce0272b447
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 719 additions and 654 deletions

View File

@ -1,9 +1,13 @@
<?php <?php
declare(strict_types=1);
namespace GraphQL\Tests\Server\Psr7; namespace GraphQL\Tests\Server\Psr7;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface; use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface; use Psr\Http\Message\UriInterface;
use function strtolower;
class PsrRequestStub implements ServerRequestInterface class PsrRequestStub implements ServerRequestInterface
{ {
@ -13,14 +17,10 @@ class PsrRequestStub implements ServerRequestInterface
public $method; public $method;
/** /** @var PsrStreamStub */
* @var PsrStreamStub
*/
public $body; public $body;
/** /** @var mixed[] */
* @var array
*/
public $parsedBody; public $parsedBody;
/** /**
@ -32,7 +32,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function getProtocolVersion() public function getProtocolVersion()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -50,7 +50,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function withProtocolVersion($version) public function withProtocolVersion($version)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -80,7 +80,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function getHeaders() public function getHeaders()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -93,7 +93,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function hasHeader($name) public function hasHeader($name)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -113,7 +113,8 @@ class PsrRequestStub implements ServerRequestInterface
public function getHeader($name) public function getHeader($name)
{ {
$name = strtolower($name); $name = strtolower($name);
return isset($this->headers[$name]) ? $this->headers[$name] : [];
return $this->headers[$name] ?? [];
} }
/** /**
@ -137,7 +138,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function getHeaderLine($name) public function getHeaderLine($name)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -150,14 +151,14 @@ class PsrRequestStub implements ServerRequestInterface
* immutability of the message, and MUST return an instance that has the * immutability of the message, and MUST return an instance that has the
* new and/or updated header and value. * new and/or updated header and value.
* *
* @param string $name Case-insensitive header field name. * @param string $name Case-insensitive header field name.
* @param string|string[] $value Header value(s). * @param string|string[] $value Header value(s).
* @return static * @return static
* @throws \InvalidArgumentException for invalid header names or values. * @throws \InvalidArgumentException for invalid header names or values.
*/ */
public function withHeader($name, $value) public function withHeader($name, $value)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -171,14 +172,14 @@ class PsrRequestStub implements ServerRequestInterface
* immutability of the message, and MUST return an instance that has the * immutability of the message, and MUST return an instance that has the
* new header and/or value. * new header and/or value.
* *
* @param string $name Case-insensitive header field name to add. * @param string $name Case-insensitive header field name to add.
* @param string|string[] $value Header value(s). * @param string|string[] $value Header value(s).
* @return static * @return static
* @throws \InvalidArgumentException for invalid header names or values. * @throws \InvalidArgumentException for invalid header names or values.
*/ */
public function withAddedHeader($name, $value) public function withAddedHeader($name, $value)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -195,7 +196,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function withoutHeader($name) public function withoutHeader($name)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -223,7 +224,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function withBody(StreamInterface $body) public function withBody(StreamInterface $body)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -244,7 +245,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function getRequestTarget() public function getRequestTarget()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -266,7 +267,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function withRequestTarget($requestTarget) public function withRequestTarget($requestTarget)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -296,7 +297,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function withMethod($method) public function withMethod($method)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -339,13 +340,13 @@ class PsrRequestStub implements ServerRequestInterface
* new UriInterface instance. * new UriInterface instance.
* *
* @link http://tools.ietf.org/html/rfc3986#section-4.3 * @link http://tools.ietf.org/html/rfc3986#section-4.3
* @param UriInterface $uri New request URI to use. * @param UriInterface $uri New request URI to use.
* @param bool $preserveHost Preserve the original state of the Host header. * @param bool $preserveHost Preserve the original state of the Host header.
* @return static * @return static
*/ */
public function withUri(UriInterface $uri, $preserveHost = false) public function withUri(UriInterface $uri, $preserveHost = false)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -359,7 +360,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function getServerParams() public function getServerParams()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -374,7 +375,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function getCookieParams() public function getCookieParams()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -396,7 +397,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function withCookieParams(array $cookies) public function withCookieParams(array $cookies)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -440,7 +441,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function withQueryParams(array $query) public function withQueryParams(array $query)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -457,7 +458,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function getUploadedFiles() public function getUploadedFiles()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -473,7 +474,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function withUploadedFiles(array $uploadedFiles) public function withUploadedFiles(array $uploadedFiles)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -526,7 +527,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function withParsedBody($data) public function withParsedBody($data)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -542,7 +543,7 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function getAttributes() public function getAttributes()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -556,13 +557,13 @@ class PsrRequestStub implements ServerRequestInterface
* specifying a default value to return if the attribute is not found. * specifying a default value to return if the attribute is not found.
* *
* @see getAttributes() * @see getAttributes()
* @param string $name The attribute name. * @param string $name The attribute name.
* @param mixed $default Default value to return if the attribute does not exist. * @param mixed $default Default value to return if the attribute does not exist.
* @return mixed * @return mixed
*/ */
public function getAttribute($name, $default = null) public function getAttribute($name, $default = null)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -576,13 +577,13 @@ class PsrRequestStub implements ServerRequestInterface
* updated attribute. * updated attribute.
* *
* @see getAttributes() * @see getAttributes()
* @param string $name The attribute name. * @param string $name The attribute name.
* @param mixed $value The value of the attribute. * @param mixed $value The value of the attribute.
* @return static * @return static
*/ */
public function withAttribute($name, $value) public function withAttribute($name, $value)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -601,6 +602,6 @@ class PsrRequestStub implements ServerRequestInterface
*/ */
public function withoutAttribute($name) public function withoutAttribute($name)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
} }

View File

@ -1,6 +1,8 @@
<?php <?php
namespace GraphQL\Tests\Server\Psr7;
declare(strict_types=1);
namespace GraphQL\Tests\Server\Psr7;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface; use Psr\Http\Message\StreamInterface;
@ -22,7 +24,7 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function getProtocolVersion() public function getProtocolVersion()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -40,7 +42,7 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function withProtocolVersion($version) public function withProtocolVersion($version)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -70,7 +72,7 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function getHeaders() public function getHeaders()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -83,7 +85,7 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function hasHeader($name) public function hasHeader($name)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -102,7 +104,7 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function getHeader($name) public function getHeader($name)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -126,7 +128,7 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function getHeaderLine($name) public function getHeaderLine($name)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -139,15 +141,16 @@ class PsrResponseStub implements ResponseInterface
* immutability of the message, and MUST return an instance that has the * immutability of the message, and MUST return an instance that has the
* new and/or updated header and value. * new and/or updated header and value.
* *
* @param string $name Case-insensitive header field name. * @param string $name Case-insensitive header field name.
* @param string|string[] $value Header value(s). * @param string|string[] $value Header value(s).
* @return static * @return static
* @throws \InvalidArgumentException for invalid header names or values. * @throws \InvalidArgumentException for invalid header names or values.
*/ */
public function withHeader($name, $value) public function withHeader($name, $value)
{ {
$tmp = clone $this; $tmp = clone $this;
$tmp->headers[$name][] = $value; $tmp->headers[$name][] = $value;
return $tmp; return $tmp;
} }
@ -162,14 +165,14 @@ class PsrResponseStub implements ResponseInterface
* immutability of the message, and MUST return an instance that has the * immutability of the message, and MUST return an instance that has the
* new header and/or value. * new header and/or value.
* *
* @param string $name Case-insensitive header field name to add. * @param string $name Case-insensitive header field name to add.
* @param string|string[] $value Header value(s). * @param string|string[] $value Header value(s).
* @return static * @return static
* @throws \InvalidArgumentException for invalid header names or values. * @throws \InvalidArgumentException for invalid header names or values.
*/ */
public function withAddedHeader($name, $value) public function withAddedHeader($name, $value)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -186,7 +189,7 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function withoutHeader($name) public function withoutHeader($name)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -196,7 +199,7 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function getBody() public function getBody()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -214,8 +217,9 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function withBody(StreamInterface $body) public function withBody(StreamInterface $body)
{ {
$tmp = clone $this; $tmp = clone $this;
$tmp->body = $body; $tmp->body = $body;
return $tmp; return $tmp;
} }
@ -229,7 +233,7 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function getStatusCode() public function getStatusCode()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -245,7 +249,7 @@ class PsrResponseStub implements ResponseInterface
* *
* @link http://tools.ietf.org/html/rfc7231#section-6 * @link http://tools.ietf.org/html/rfc7231#section-6
* @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
* @param int $code The 3-digit integer result code to set. * @param int $code The 3-digit integer result code to set.
* @param string $reasonPhrase The reason phrase to use with the * @param string $reasonPhrase The reason phrase to use with the
* provided status code; if none is provided, implementations MAY * provided status code; if none is provided, implementations MAY
* use the defaults as suggested in the HTTP specification. * use the defaults as suggested in the HTTP specification.
@ -254,8 +258,9 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function withStatus($code, $reasonPhrase = '') public function withStatus($code, $reasonPhrase = '')
{ {
$tmp = clone $this; $tmp = clone $this;
$tmp->statusCode = $code; $tmp->statusCode = $code;
return $tmp; return $tmp;
} }
@ -274,6 +279,6 @@ class PsrResponseStub implements ResponseInterface
*/ */
public function getReasonPhrase() public function getReasonPhrase()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
} }

View File

@ -1,7 +1,12 @@
<?php <?php
declare(strict_types=1);
namespace GraphQL\Tests\Server\Psr7; namespace GraphQL\Tests\Server\Psr7;
use Psr\Http\Message\StreamInterface; use Psr\Http\Message\StreamInterface;
use function strlen;
use const SEEK_SET;
class PsrStreamStub implements StreamInterface class PsrStreamStub implements StreamInterface
{ {
@ -33,7 +38,7 @@ class PsrStreamStub implements StreamInterface
*/ */
public function close() public function close()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -45,7 +50,7 @@ class PsrStreamStub implements StreamInterface
*/ */
public function detach() public function detach()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -55,7 +60,7 @@ class PsrStreamStub implements StreamInterface
*/ */
public function getSize() public function getSize()
{ {
return strlen($this->content?:''); return strlen($this->content ?: '');
} }
/** /**
@ -66,7 +71,7 @@ class PsrStreamStub implements StreamInterface
*/ */
public function tell() public function tell()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -76,7 +81,7 @@ class PsrStreamStub implements StreamInterface
*/ */
public function eof() public function eof()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -86,7 +91,7 @@ class PsrStreamStub implements StreamInterface
*/ */
public function isSeekable() public function isSeekable()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -103,7 +108,7 @@ class PsrStreamStub implements StreamInterface
*/ */
public function seek($offset, $whence = SEEK_SET) public function seek($offset, $whence = SEEK_SET)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -118,7 +123,7 @@ class PsrStreamStub implements StreamInterface
*/ */
public function rewind() public function rewind()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -141,6 +146,7 @@ class PsrStreamStub implements StreamInterface
public function write($string) public function write($string)
{ {
$this->content = $string; $this->content = $string;
return strlen($string); return strlen($string);
} }
@ -151,7 +157,7 @@ class PsrStreamStub implements StreamInterface
*/ */
public function isReadable() public function isReadable()
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -166,7 +172,7 @@ class PsrStreamStub implements StreamInterface
*/ */
public function read($length) public function read($length)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
/** /**
@ -195,6 +201,6 @@ class PsrStreamStub implements StreamInterface
*/ */
public function getMetadata($key = null) public function getMetadata($key = null)
{ {
throw new \Exception("Not implemented"); throw new \Exception('Not implemented');
} }
} }

View File

@ -1,18 +1,22 @@
<?php <?php
declare(strict_types=1);
namespace GraphQL\Tests\Server; namespace GraphQL\Tests\Server;
use GraphQL\Executor\ExecutionResult; use GraphQL\Executor\ExecutionResult;
use GraphQL\Server\Helper; use GraphQL\Server\Helper;
use GraphQL\Tests\Server\Psr7\PsrStreamStub;
use GraphQL\Tests\Server\Psr7\PsrResponseStub; use GraphQL\Tests\Server\Psr7\PsrResponseStub;
use GraphQL\Tests\Server\Psr7\PsrStreamStub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use function json_encode;
class PsrResponseTest extends TestCase class PsrResponseTest extends TestCase
{ {
public function testConvertsResultToPsrResponse() : void public function testConvertsResultToPsrResponse() : void
{ {
$result = new ExecutionResult(['key' => 'value']); $result = new ExecutionResult(['key' => 'value']);
$stream = new PsrStreamStub(); $stream = new PsrStreamStub();
$psrResponse = new PsrResponseStub(); $psrResponse = new PsrResponseStub();
$helper = new Helper(); $helper = new Helper();

View File

@ -1,11 +1,12 @@
<?php <?php
declare(strict_types=1);
namespace GraphQL\Tests\Server; namespace GraphQL\Tests\Server;
use GraphQL\Deferred;
use GraphQL\Error\Debug; use GraphQL\Error\Debug;
use GraphQL\Error\Error; use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation; use GraphQL\Error\InvariantViolation;
use GraphQL\Error\UserError;
use GraphQL\Executor\ExecutionResult; use GraphQL\Executor\ExecutionResult;
use GraphQL\Language\AST\DocumentNode; use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\Parser; use GraphQL\Language\Parser;
@ -16,17 +17,17 @@ use GraphQL\Server\ServerConfig;
use GraphQL\Validator\DocumentValidator; use GraphQL\Validator\DocumentValidator;
use GraphQL\Validator\Rules\CustomValidationRule; use GraphQL\Validator\Rules\CustomValidationRule;
use GraphQL\Validator\ValidationContext; use GraphQL\Validator\ValidationContext;
use function count;
use function sprintf;
class QueryExecutionTest extends ServerTestCase class QueryExecutionTest extends ServerTestCase
{ {
/** /** @var ServerConfig */
* @var ServerConfig
*/
private $config; private $config;
public function setUp() public function setUp()
{ {
$schema = $this->buildSchema(); $schema = $this->buildSchema();
$this->config = ServerConfig::create() $this->config = ServerConfig::create()
->setSchema($schema); ->setSchema($schema);
} }
@ -36,14 +37,30 @@ class QueryExecutionTest extends ServerTestCase
$query = '{f1}'; $query = '{f1}';
$expected = [ $expected = [
'data' => [ 'data' => ['f1' => 'f1'],
'f1' => 'f1'
]
]; ];
$this->assertQueryResultEquals($expected, $query); $this->assertQueryResultEquals($expected, $query);
} }
private function assertQueryResultEquals($expected, $query, $variables = null)
{
$result = $this->executeQuery($query, $variables);
$this->assertArraySubset($expected, $result->toArray(true));
return $result;
}
private function executeQuery($query, $variables = null, $readonly = false)
{
$op = OperationParams::create(['query' => $query, 'variables' => $variables], $readonly);
$helper = new Helper();
$result = $helper->executeOperation($this->config, $op);
$this->assertInstanceOf(ExecutionResult::class, $result);
return $result;
}
public function testReturnsSyntaxErrors() : void public function testReturnsSyntaxErrors() : void
{ {
$query = '{f1'; $query = '{f1';
@ -70,17 +87,17 @@ class QueryExecutionTest extends ServerTestCase
'; ';
$expected = [ $expected = [
'data' => [ 'data' => [
'fieldWithException' => null, 'fieldWithException' => null,
'f1' => 'f1' 'f1' => 'f1',
], ],
'errors' => [ 'errors' => [
[ [
'message' => 'This is the exception we want', 'message' => 'This is the exception we want',
'path' => ['fieldWithException'], 'path' => ['fieldWithException'],
'trace' => [] 'trace' => [],
] ],
] ],
]; ];
$result = $this->executeQuery($query)->toArray(); $result = $this->executeQuery($query)->toArray();
@ -90,7 +107,7 @@ class QueryExecutionTest extends ServerTestCase
public function testPassesRootValueAndContext() : void public function testPassesRootValueAndContext() : void
{ {
$rootValue = 'myRootValue'; $rootValue = 'myRootValue';
$context = new \stdClass(); $context = new \stdClass();
$this->config $this->config
->setContext($context) ->setContext($context)
@ -102,7 +119,7 @@ class QueryExecutionTest extends ServerTestCase
} }
'; ';
$this->assertTrue(!isset($context->testedRootValue)); $this->assertTrue(! isset($context->testedRootValue));
$this->executeQuery($query); $this->executeQuery($query);
$this->assertSame($rootValue, $context->testedRootValue); $this->assertSame($rootValue, $context->testedRootValue);
} }
@ -110,30 +127,30 @@ class QueryExecutionTest extends ServerTestCase
public function testPassesVariables() : void public function testPassesVariables() : void
{ {
$variables = ['a' => 'a', 'b' => 'b']; $variables = ['a' => 'a', 'b' => 'b'];
$query = ' $query = '
query ($a: String!, $b: String!) { query ($a: String!, $b: String!) {
a: fieldWithArg(arg: $a) a: fieldWithArg(arg: $a)
b: fieldWithArg(arg: $b) b: fieldWithArg(arg: $b)
} }
'; ';
$expected = [ $expected = [
'data' => [ 'data' => [
'a' => 'a', 'a' => 'a',
'b' => 'b' 'b' => 'b',
] ],
]; ];
$this->assertQueryResultEquals($expected, $query, $variables); $this->assertQueryResultEquals($expected, $query, $variables);
} }
public function testPassesCustomValidationRules() : void public function testPassesCustomValidationRules() : void
{ {
$query = ' $query = '
{nonExistentField} {nonExistentField}
'; ';
$expected = [ $expected = [
'errors' => [ 'errors' => [
['message' => 'Cannot query field "nonExistentField" on type "Query".'] ['message' => 'Cannot query field "nonExistentField" on type "Query".'],
] ],
]; ];
$this->assertQueryResultEquals($expected, $query); $this->assertQueryResultEquals($expected, $query);
@ -141,15 +158,16 @@ class QueryExecutionTest extends ServerTestCase
$called = false; $called = false;
$rules = [ $rules = [
new CustomValidationRule('SomeRule', function() use (&$called) { new CustomValidationRule('SomeRule', function () use (&$called) {
$called = true; $called = true;
return []; return [];
}) }),
]; ];
$this->config->setValidationRules($rules); $this->config->setValidationRules($rules);
$expected = [ $expected = [
'data' => [] 'data' => [],
]; ];
$this->assertQueryResultEquals($expected, $query); $this->assertQueryResultEquals($expected, $query);
$this->assertTrue($called); $this->assertTrue($called);
@ -160,11 +178,12 @@ class QueryExecutionTest extends ServerTestCase
$called = false; $called = false;
$params = $doc = $operationType = null; $params = $doc = $operationType = null;
$this->config->setValidationRules(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) { $this->config->setValidationRules(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
$called = true; $called = true;
$params = $p; $params = $p;
$doc = $d; $doc = $d;
$operationType = $o; $operationType = $o;
return []; return [];
}); });
@ -178,23 +197,25 @@ class QueryExecutionTest extends ServerTestCase
public function testAllowsDifferentValidationRulesDependingOnOperation() : void public function testAllowsDifferentValidationRulesDependingOnOperation() : void
{ {
$q1 = '{f1}'; $q1 = '{f1}';
$q2 = '{invalid}'; $q2 = '{invalid}';
$called1 = false; $called1 = false;
$called2 = false; $called2 = false;
$this->config->setValidationRules(function(OperationParams $params) use ($q1, $q2, &$called1, &$called2) { $this->config->setValidationRules(function (OperationParams $params) use ($q1, $q2, &$called1, &$called2) {
if ($params->query === $q1) { if ($params->query === $q1) {
$called1 = true; $called1 = true;
return DocumentValidator::allRules(); return DocumentValidator::allRules();
} else {
$called2 = true;
return [
new CustomValidationRule('MyRule', function(ValidationContext $context) {
$context->reportError(new Error("This is the error we are looking for!"));
})
];
} }
$called2 = true;
return [
new CustomValidationRule('MyRule', function (ValidationContext $context) {
$context->reportError(new Error('This is the error we are looking for!'));
}),
];
}); });
$expected = ['data' => ['f1' => 'f1']]; $expected = ['data' => ['f1' => 'f1']];
@ -202,8 +223,8 @@ class QueryExecutionTest extends ServerTestCase
$this->assertTrue($called1); $this->assertTrue($called1);
$this->assertFalse($called2); $this->assertFalse($called2);
$called1 = false; $called1 = false;
$called2 = false; $called2 = false;
$expected = ['errors' => [['message' => 'This is the error we are looking for!']]]; $expected = ['errors' => [['message' => 'This is the error we are looking for!']]];
$this->assertQueryResultEquals($expected, $q2); $this->assertQueryResultEquals($expected, $q2);
$this->assertFalse($called1); $this->assertFalse($called1);
@ -213,7 +234,7 @@ class QueryExecutionTest extends ServerTestCase
public function testAllowsSkippingValidation() : void public function testAllowsSkippingValidation() : void
{ {
$this->config->setValidationRules([]); $this->config->setValidationRules([]);
$query = '{nonExistentField}'; $query = '{nonExistentField}';
$expected = ['data' => []]; $expected = ['data' => []];
$this->assertQueryResultEquals($expected, $query); $this->assertQueryResultEquals($expected, $query);
} }
@ -225,23 +246,29 @@ class QueryExecutionTest extends ServerTestCase
$expected = [ $expected = [
'errors' => [ 'errors' => [
[ [
'message' => 'Persisted queries are not supported by this server', 'message' => 'Persisted queries are not supported by this server',
'category' => 'request' 'category' => 'request',
] ],
] ],
]; ];
$this->assertEquals($expected, $result->toArray()); $this->assertEquals($expected, $result->toArray());
} }
private function executePersistedQuery($queryId, $variables = null)
{
$op = OperationParams::create(['queryId' => $queryId, 'variables' => $variables]);
$helper = new Helper();
$result = $helper->executeOperation($this->config, $op);
$this->assertInstanceOf(ExecutionResult::class, $result);
return $result;
}
public function testBatchedQueriesAreDisabledByDefault() : void public function testBatchedQueriesAreDisabledByDefault() : void
{ {
$batch = [ $batch = [
[ ['query' => '{invalid}'],
'query' => '{invalid}' ['query' => '{f1,fieldWithException}'],
],
[
'query' => '{f1,fieldWithException}'
]
]; ];
$result = $this->executeBatchedQuery($batch); $result = $this->executeBatchedQuery($batch);
@ -250,18 +277,18 @@ class QueryExecutionTest extends ServerTestCase
[ [
'errors' => [ 'errors' => [
[ [
'message' => 'Batched queries are not supported by this server', 'message' => 'Batched queries are not supported by this server',
'category' => 'request' 'category' => 'request',
] ],
] ],
], ],
[ [
'errors' => [ 'errors' => [
[ [
'message' => 'Batched queries are not supported by this server', 'message' => 'Batched queries are not supported by this server',
'category' => 'request' 'category' => 'request',
] ],
] ],
], ],
]; ];
@ -269,6 +296,31 @@ class QueryExecutionTest extends ServerTestCase
$this->assertEquals($expected[1], $result[1]->toArray()); $this->assertEquals($expected[1], $result[1]->toArray());
} }
/**
* @param mixed[][] $qs
*/
private function executeBatchedQuery(array $qs)
{
$batch = [];
foreach ($qs as $params) {
$batch[] = OperationParams::create($params);
}
$helper = new Helper();
$result = $helper->executeBatch($this->config, $batch);
$this->assertInternalType('array', $result);
$this->assertCount(count($qs), $result);
foreach ($result as $index => $entry) {
$this->assertInstanceOf(
ExecutionResult::class,
$entry,
sprintf('Result at %s is not an instance of %s', $index, ExecutionResult::class)
);
}
return $result;
}
public function testMutationsAreNotAllowedInReadonlyMode() : void public function testMutationsAreNotAllowedInReadonlyMode() : void
{ {
$mutation = 'mutation { a }'; $mutation = 'mutation { a }';
@ -276,10 +328,10 @@ class QueryExecutionTest extends ServerTestCase
$expected = [ $expected = [
'errors' => [ 'errors' => [
[ [
'message' => 'GET supports only query operation', 'message' => 'GET supports only query operation',
'category' => 'request' 'category' => 'request',
] ],
] ],
]; ];
$result = $this->executeQuery($mutation, null, true); $result = $this->executeQuery($mutation, null, true);
@ -289,9 +341,10 @@ class QueryExecutionTest extends ServerTestCase
public function testAllowsPersistentQueries() : void public function testAllowsPersistentQueries() : void
{ {
$called = false; $called = false;
$this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) { $this->config->setPersistentQueryLoader(function ($queryId, OperationParams $params) use (&$called) {
$called = true; $called = true;
$this->assertEquals('some-id', $queryId); $this->assertEquals('some-id', $queryId);
return '{f1}'; return '{f1}';
}); });
@ -299,17 +352,16 @@ class QueryExecutionTest extends ServerTestCase
$this->assertTrue($called); $this->assertTrue($called);
$expected = [ $expected = [
'data' => [ 'data' => ['f1' => 'f1'],
'f1' => 'f1'
]
]; ];
$this->assertEquals($expected, $result->toArray()); $this->assertEquals($expected, $result->toArray());
// Make sure it allows returning document node: // Make sure it allows returning document node:
$called = false; $called = false;
$this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) { $this->config->setPersistentQueryLoader(function ($queryId, OperationParams $params) use (&$called) {
$called = true; $called = true;
$this->assertEquals('some-id', $queryId); $this->assertEquals('some-id', $queryId);
return Parser::parse('{f1}'); return Parser::parse('{f1}');
}); });
$result = $this->executePersistedQuery('some-id'); $result = $this->executePersistedQuery('some-id');
@ -324,7 +376,7 @@ class QueryExecutionTest extends ServerTestCase
'Persistent query loader must return query string or instance of GraphQL\Language\AST\DocumentNode ' . 'Persistent query loader must return query string or instance of GraphQL\Language\AST\DocumentNode ' .
'but got: {"err":"err"}' 'but got: {"err":"err"}'
); );
$this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) { $this->config->setPersistentQueryLoader(function ($queryId, OperationParams $params) use (&$called) {
return ['err' => 'err']; return ['err' => 'err'];
}); });
$this->executePersistedQuery('some-id'); $this->executePersistedQuery('some-id');
@ -332,56 +384,55 @@ class QueryExecutionTest extends ServerTestCase
public function testPersistedQueriesAreStillValidatedByDefault() : void public function testPersistedQueriesAreStillValidatedByDefault() : void
{ {
$this->config->setPersistentQueryLoader(function() { $this->config->setPersistentQueryLoader(function () {
return '{invalid}'; return '{invalid}';
}); });
$result = $this->executePersistedQuery('some-id'); $result = $this->executePersistedQuery('some-id');
$expected = [ $expected = [
'errors' => [ 'errors' => [
[ [
'message' => 'Cannot query field "invalid" on type "Query".', 'message' => 'Cannot query field "invalid" on type "Query".',
'locations' => [ ['line' => 1, 'column' => 2] ], 'locations' => [['line' => 1, 'column' => 2]],
'category' => 'graphql' 'category' => 'graphql',
] ],
] ],
]; ];
$this->assertEquals($expected, $result->toArray()); $this->assertEquals($expected, $result->toArray());
} }
public function testAllowSkippingValidationForPersistedQueries() : void public function testAllowSkippingValidationForPersistedQueries() : void
{ {
$this->config $this->config
->setPersistentQueryLoader(function($queryId) { ->setPersistentQueryLoader(function ($queryId) {
if ($queryId === 'some-id') { if ($queryId === 'some-id') {
return '{invalid}'; return '{invalid}';
} else {
return '{invalid2}';
} }
return '{invalid2}';
}) })
->setValidationRules(function(OperationParams $params) { ->setValidationRules(function (OperationParams $params) {
if ($params->queryId === 'some-id') { if ($params->queryId === 'some-id') {
return []; return [];
} else {
return DocumentValidator::allRules();
} }
return DocumentValidator::allRules();
}); });
$result = $this->executePersistedQuery('some-id'); $result = $this->executePersistedQuery('some-id');
$expected = [ $expected = [
'data' => [] 'data' => [],
]; ];
$this->assertEquals($expected, $result->toArray()); $this->assertEquals($expected, $result->toArray());
$result = $this->executePersistedQuery('some-other-id'); $result = $this->executePersistedQuery('some-other-id');
$expected = [ $expected = [
'errors' => [ 'errors' => [
[ [
'message' => 'Cannot query field "invalid2" on type "Query".', 'message' => 'Cannot query field "invalid2" on type "Query".',
'locations' => [ ['line' => 1, 'column' => 2] ], 'locations' => [['line' => 1, 'column' => 2]],
'category' => 'graphql' 'category' => 'graphql',
] ],
] ],
]; ];
$this->assertEquals($expected, $result->toArray()); $this->assertEquals($expected, $result->toArray());
} }
@ -390,7 +441,7 @@ class QueryExecutionTest extends ServerTestCase
{ {
$this->expectException(InvariantViolation::class); $this->expectException(InvariantViolation::class);
$this->expectExceptionMessage('Expecting validation rules to be array or callable returning array, but got: instance of stdClass'); $this->expectExceptionMessage('Expecting validation rules to be array or callable returning array, but got: instance of stdClass');
$this->config->setValidationRules(function(OperationParams $params) { $this->config->setValidationRules(function (OperationParams $params) {
return new \stdClass(); return new \stdClass();
}); });
$this->executeQuery('{f1}'); $this->executeQuery('{f1}');
@ -401,44 +452,40 @@ class QueryExecutionTest extends ServerTestCase
$this->config->setQueryBatching(true); $this->config->setQueryBatching(true);
$batch = [ $batch = [
['query' => '{invalid}'],
['query' => '{f1,fieldWithException}'],
[ [
'query' => '{invalid}' 'query' => '
],
[
'query' => '{f1,fieldWithException}'
],
[
'query' => '
query ($a: String!, $b: String!) { query ($a: String!, $b: String!) {
a: fieldWithArg(arg: $a) a: fieldWithArg(arg: $a)
b: fieldWithArg(arg: $b) b: fieldWithArg(arg: $b)
} }
', ',
'variables' => ['a' => 'a', 'b' => 'b'], 'variables' => ['a' => 'a', 'b' => 'b'],
] ],
]; ];
$result = $this->executeBatchedQuery($batch); $result = $this->executeBatchedQuery($batch);
$expected = [ $expected = [
[ [
'errors' => [['message' => 'Cannot query field "invalid" on type "Query".']] 'errors' => [['message' => 'Cannot query field "invalid" on type "Query".']],
], ],
[ [
'data' => [ 'data' => [
'f1' => 'f1', 'f1' => 'f1',
'fieldWithException' => null 'fieldWithException' => null,
], ],
'errors' => [ 'errors' => [
['message' => 'This is the exception we want'] ['message' => 'This is the exception we want'],
] ],
], ],
[ [
'data' => [ 'data' => [
'a' => 'a', 'a' => 'a',
'b' => 'b' 'b' => 'b',
] ],
] ],
]; ];
$this->assertArraySubset($expected[0], $result[0]->toArray()); $this->assertArraySubset($expected[0], $result[0]->toArray());
@ -449,15 +496,9 @@ class QueryExecutionTest extends ServerTestCase
public function testDeferredsAreSharedAmongAllBatchedQueries() : void public function testDeferredsAreSharedAmongAllBatchedQueries() : void
{ {
$batch = [ $batch = [
[ ['query' => '{dfd(num: 1)}'],
'query' => '{dfd(num: 1)}' ['query' => '{dfd(num: 2)}'],
], ['query' => '{dfd(num: 3)}'],
[
'query' => '{dfd(num: 2)}'
],
[
'query' => '{dfd(num: 3)}',
]
]; ];
$calls = []; $calls = [];
@ -466,13 +507,14 @@ class QueryExecutionTest extends ServerTestCase
->setQueryBatching(true) ->setQueryBatching(true)
->setRootValue('1') ->setRootValue('1')
->setContext([ ->setContext([
'buffer' => function($num) use (&$calls) { 'buffer' => function ($num) use (&$calls) {
$calls[] = "buffer: $num"; $calls[] = sprintf('buffer: %d', $num);
},
'load' => function ($num) use (&$calls) {
$calls[] = sprintf('load: %d', $num);
return sprintf('loaded: %d', $num);
}, },
'load' => function($num) use (&$calls) {
$calls[] = "load: $num";
return "loaded: $num";
}
]); ]);
$result = $this->executeBatchedQuery($batch); $result = $this->executeBatchedQuery($batch);
@ -489,19 +531,13 @@ class QueryExecutionTest extends ServerTestCase
$expected = [ $expected = [
[ [
'data' => [ 'data' => ['dfd' => 'loaded: 1'],
'dfd' => 'loaded: 1'
]
], ],
[ [
'data' => [ 'data' => ['dfd' => 'loaded: 2'],
'dfd' => 'loaded: 2'
]
], ],
[ [
'data' => [ 'data' => ['dfd' => 'loaded: 3'],
'dfd' => 'loaded: 3'
]
], ],
]; ];
@ -512,7 +548,7 @@ class QueryExecutionTest extends ServerTestCase
public function testValidatesParamsBeforeExecution() : void public function testValidatesParamsBeforeExecution() : void
{ {
$op = OperationParams::create(['queryBad' => '{f1}']); $op = OperationParams::create(['queryBad' => '{f1}']);
$helper = new Helper(); $helper = new Helper();
$result = $helper->executeOperation($this->config, $op); $result = $helper->executeOperation($this->config, $op);
$this->assertInstanceOf(ExecutionResult::class, $result); $this->assertInstanceOf(ExecutionResult::class, $result);
@ -536,10 +572,10 @@ class QueryExecutionTest extends ServerTestCase
$called = false; $called = false;
$params = $doc = $operationType = null; $params = $doc = $operationType = null;
$this->config->setContext(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) { $this->config->setContext(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
$called = true; $called = true;
$params = $p; $params = $p;
$doc = $d; $doc = $d;
$operationType = $o; $operationType = $o;
}); });
@ -556,10 +592,10 @@ class QueryExecutionTest extends ServerTestCase
$called = false; $called = false;
$params = $doc = $operationType = null; $params = $doc = $operationType = null;
$this->config->setRootValue(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) { $this->config->setRootValue(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
$called = true; $called = true;
$params = $p; $params = $p;
$doc = $d; $doc = $d;
$operationType = $o; $operationType = $o;
}); });
@ -574,20 +610,21 @@ class QueryExecutionTest extends ServerTestCase
public function testAppliesErrorFormatter() : void public function testAppliesErrorFormatter() : void
{ {
$called = false; $called = false;
$error = null; $error = null;
$this->config->setErrorFormatter(function($e) use (&$called, &$error) { $this->config->setErrorFormatter(function ($e) use (&$called, &$error) {
$called = true; $called = true;
$error = $e; $error = $e;
return ['test' => 'formatted']; return ['test' => 'formatted'];
}); });
$result = $this->executeQuery('{fieldWithException}'); $result = $this->executeQuery('{fieldWithException}');
$this->assertFalse($called); $this->assertFalse($called);
$formatted = $result->toArray(); $formatted = $result->toArray();
$expected = [ $expected = [
'errors' => [ 'errors' => [
['test' => 'formatted'] ['test' => 'formatted'],
] ],
]; ];
$this->assertTrue($called); $this->assertTrue($called);
$this->assertArraySubset($expected, $formatted); $this->assertArraySubset($expected, $formatted);
@ -595,28 +632,29 @@ class QueryExecutionTest extends ServerTestCase
// Assert debugging still works even with custom formatter // Assert debugging still works even with custom formatter
$formatted = $result->toArray(Debug::INCLUDE_TRACE); $formatted = $result->toArray(Debug::INCLUDE_TRACE);
$expected = [ $expected = [
'errors' => [ 'errors' => [
[ [
'test' => 'formatted', 'test' => 'formatted',
'trace' => [] 'trace' => [],
] ],
] ],
]; ];
$this->assertArraySubset($expected, $formatted); $this->assertArraySubset($expected, $formatted);
} }
public function testAppliesErrorsHandler() : void public function testAppliesErrorsHandler() : void
{ {
$called = false; $called = false;
$errors = null; $errors = null;
$formatter = null; $formatter = null;
$this->config->setErrorsHandler(function($e, $f) use (&$called, &$errors, &$formatter) { $this->config->setErrorsHandler(function ($e, $f) use (&$called, &$errors, &$formatter) {
$called = true; $called = true;
$errors = $e; $errors = $e;
$formatter = $f; $formatter = $f;
return [ return [
['test' => 'handled'] ['test' => 'handled'],
]; ];
}); });
@ -624,10 +662,10 @@ class QueryExecutionTest extends ServerTestCase
$this->assertFalse($called); $this->assertFalse($called);
$formatted = $result->toArray(); $formatted = $result->toArray();
$expected = [ $expected = [
'errors' => [ 'errors' => [
['test' => 'handled'] ['test' => 'handled'],
] ],
]; ];
$this->assertTrue($called); $this->assertTrue($called);
$this->assertArraySubset($expected, $formatted); $this->assertArraySubset($expected, $formatted);
@ -636,46 +674,4 @@ class QueryExecutionTest extends ServerTestCase
$this->assertInternalType('callable', $formatter); $this->assertInternalType('callable', $formatter);
$this->assertArraySubset($expected, $formatted); $this->assertArraySubset($expected, $formatted);
} }
private function executePersistedQuery($queryId, $variables = null)
{
$op = OperationParams::create(['queryId' => $queryId, 'variables' => $variables]);
$helper = new Helper();
$result = $helper->executeOperation($this->config, $op);
$this->assertInstanceOf(ExecutionResult::class, $result);
return $result;
}
private function executeQuery($query, $variables = null, $readonly = false)
{
$op = OperationParams::create(['query' => $query, 'variables' => $variables], $readonly);
$helper = new Helper();
$result = $helper->executeOperation($this->config, $op);
$this->assertInstanceOf(ExecutionResult::class, $result);
return $result;
}
private function executeBatchedQuery(array $qs)
{
$batch = [];
foreach ($qs as $params) {
$batch[] = OperationParams::create($params);
}
$helper = new Helper();
$result = $helper->executeBatch($this->config, $batch);
$this->assertInternalType('array', $result);
$this->assertCount(count($qs), $result);
foreach ($result as $index => $entry) {
$this->assertInstanceOf(ExecutionResult::class, $entry, "Result at $index is not an instance of " . ExecutionResult::class);
}
return $result;
}
private function assertQueryResultEquals($expected, $query, $variables = null)
{
$result = $this->executeQuery($query, $variables);
$this->assertArraySubset($expected, $result->toArray(true));
return $result;
}
} }

View File

@ -1,7 +1,9 @@
<?php <?php
declare(strict_types=1);
namespace GraphQL\Tests\Server; namespace GraphQL\Tests\Server;
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation; use GraphQL\Error\InvariantViolation;
use GraphQL\Server\Helper; use GraphQL\Server\Helper;
use GraphQL\Server\OperationParams; use GraphQL\Server\OperationParams;
@ -9,15 +11,17 @@ use GraphQL\Server\RequestError;
use GraphQL\Tests\Server\Psr7\PsrRequestStub; use GraphQL\Tests\Server\Psr7\PsrRequestStub;
use GraphQL\Tests\Server\Psr7\PsrStreamStub; use GraphQL\Tests\Server\Psr7\PsrStreamStub;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use function json_decode;
use function json_encode;
class RequestParsingTest extends TestCase class RequestParsingTest extends TestCase
{ {
public function testParsesGraphqlRequest() : void public function testParsesGraphqlRequest() : void
{ {
$query = '{my query}'; $query = '{my query}';
$parsed = [ $parsed = [
'raw' => $this->parseRawRequest('application/graphql', $query), 'raw' => $this->parseRawRequest('application/graphql', $query),
'psr' => $this->parsePsrRequest('application/graphql', $query) 'psr' => $this->parsePsrRequest('application/graphql', $query),
]; ];
foreach ($parsed as $source => $parsedBody) { foreach ($parsed as $source => $parsedBody) {
@ -26,20 +30,91 @@ class RequestParsingTest extends TestCase
} }
} }
/**
* @param string $contentType
* @param string $content
*
* @return OperationParams|OperationParams[]
*/
private function parseRawRequest($contentType, $content, string $method = 'POST')
{
$_SERVER['CONTENT_TYPE'] = $contentType;
$_SERVER['REQUEST_METHOD'] = $method;
$helper = new Helper();
return $helper->parseHttpRequest(function () use ($content) {
return $content;
});
}
/**
* @param string $contentType
* @param string $content
*
* @return OperationParams|OperationParams[]
*/
private function parsePsrRequest($contentType, $content, string $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);
}
/**
* @param OperationParams $params
* @param string $query
* @param string $queryId
* @param mixed|null $variables
* @param string $operation
*/
private function assertValidOperationParams(
$params,
$query,
$queryId = null,
$variables = null,
$operation = null,
$message = ''
) {
$this->assertInstanceOf(OperationParams::class, $params, $message);
$this->assertSame($query, $params->query, $message);
$this->assertSame($queryId, $params->queryId, $message);
$this->assertSame($variables, $params->variables, $message);
$this->assertSame($operation, $params->operation, $message);
}
public function testParsesUrlencodedRequest() : void public function testParsesUrlencodedRequest() : void
{ {
$query = '{my query}'; $query = '{my query}';
$variables = ['test' => 1, 'test2' => 2]; $variables = ['test' => 1, 'test2' => 2];
$operation = 'op'; $operation = 'op';
$post = [ $post = [
'query' => $query, 'query' => $query,
'variables' => $variables, 'variables' => $variables,
'operationName' => $operation 'operationName' => $operation,
]; ];
$parsed = [ $parsed = [
'raw' => $this->parseRawFormUrlencodedRequest($post), 'raw' => $this->parseRawFormUrlencodedRequest($post),
'psr' => $this->parsePsrFormUrlEncodedRequest($post) 'psr' => $this->parsePsrFormUrlEncodedRequest($post),
]; ];
foreach ($parsed as $method => $parsedBody) { foreach ($parsed as $method => $parsedBody) {
@ -48,20 +123,53 @@ class RequestParsingTest extends TestCase
} }
} }
/**
* @param mixed[] $postValue
* @return OperationParams|OperationParams[]
*/
private function parseRawFormUrlencodedRequest($postValue)
{
$_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST = $postValue;
$helper = new Helper();
return $helper->parseHttpRequest(function () {
throw new InvariantViolation("Shouldn't read from php://input for urlencoded request");
});
}
/**
* @param mixed[] $postValue
* @return OperationParams[]|OperationParams
*/
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);
}
public function testParsesGetRequest() : void public function testParsesGetRequest() : void
{ {
$query = '{my query}'; $query = '{my query}';
$variables = ['test' => 1, 'test2' => 2]; $variables = ['test' => 1, 'test2' => 2];
$operation = 'op'; $operation = 'op';
$get = [ $get = [
'query' => $query, 'query' => $query,
'variables' => $variables, 'variables' => $variables,
'operationName' => $operation 'operationName' => $operation,
]; ];
$parsed = [ $parsed = [
'raw' => $this->parseRawGetRequest($get), 'raw' => $this->parseRawGetRequest($get),
'psr' => $this->parsePsrGetRequest($get) 'psr' => $this->parsePsrGetRequest($get),
]; ];
foreach ($parsed as $method => $parsedBody) { foreach ($parsed as $method => $parsedBody) {
@ -70,20 +178,51 @@ class RequestParsingTest extends TestCase
} }
} }
/**
* @param mixed[] $getValue
* @return OperationParams
*/
private function parseRawGetRequest($getValue)
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_GET = $getValue;
$helper = new Helper();
return $helper->parseHttpRequest(function () {
throw new InvariantViolation("Shouldn't read from php://input for urlencoded request");
});
}
/**
* @param mixed[] $getValue
* @return OperationParams[]|OperationParams
*/
private function parsePsrGetRequest($getValue)
{
$psrRequest = new PsrRequestStub();
$psrRequest->method = 'GET';
$psrRequest->queryParams = $getValue;
$helper = new Helper();
return $helper->parsePsrRequest($psrRequest);
}
public function testParsesMultipartFormdataRequest() : void public function testParsesMultipartFormdataRequest() : void
{ {
$query = '{my query}'; $query = '{my query}';
$variables = ['test' => 1, 'test2' => 2]; $variables = ['test' => 1, 'test2' => 2];
$operation = 'op'; $operation = 'op';
$post = [ $post = [
'query' => $query, 'query' => $query,
'variables' => $variables, 'variables' => $variables,
'operationName' => $operation 'operationName' => $operation,
]; ];
$parsed = [ $parsed = [
'raw' => $this->parseRawMultipartFormdataRequest($post), 'raw' => $this->parseRawMultipartFormdataRequest($post),
'psr' => $this->parsePsrMultipartFormdataRequest($post) 'psr' => $this->parsePsrMultipartFormdataRequest($post),
]; ];
foreach ($parsed as $method => $parsedBody) { foreach ($parsed as $method => $parsedBody) {
@ -92,20 +231,53 @@ class RequestParsingTest extends TestCase
} }
} }
/**
* @param mixed[] $postValue
* @return OperationParams|OperationParams[]
*/
private function parseRawMultipartFormDataRequest($postValue)
{
$_SERVER['CONTENT_TYPE'] = 'multipart/form-data; boundary=----FormBoundary';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST = $postValue;
$helper = new Helper();
return $helper->parseHttpRequest(function () {
throw new InvariantViolation("Shouldn't read from php://input for multipart/form-data request");
});
}
/**
* @param mixed[] $postValue
* @return OperationParams|OperationParams[]
*/
private function parsePsrMultipartFormDataRequest($postValue)
{
$psrRequest = new PsrRequestStub();
$psrRequest->headers['content-type'] = ['multipart/form-data; boundary=----FormBoundary'];
$psrRequest->method = 'POST';
$psrRequest->parsedBody = $postValue;
$helper = new Helper();
return $helper->parsePsrRequest($psrRequest);
}
public function testParsesJSONRequest() : void public function testParsesJSONRequest() : void
{ {
$query = '{my query}'; $query = '{my query}';
$variables = ['test' => 1, 'test2' => 2]; $variables = ['test' => 1, 'test2' => 2];
$operation = 'op'; $operation = 'op';
$body = [ $body = [
'query' => $query, 'query' => $query,
'variables' => $variables, 'variables' => $variables,
'operationName' => $operation 'operationName' => $operation,
]; ];
$parsed = [ $parsed = [
'raw' => $this->parseRawRequest('application/json', json_encode($body)), 'raw' => $this->parseRawRequest('application/json', json_encode($body)),
'psr' => $this->parsePsrRequest('application/json', json_encode($body)) 'psr' => $this->parsePsrRequest('application/json', json_encode($body)),
]; ];
foreach ($parsed as $method => $parsedBody) { foreach ($parsed as $method => $parsedBody) {
$this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method); $this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method);
@ -115,18 +287,18 @@ class RequestParsingTest extends TestCase
public function testParsesVariablesAsJSON() : void public function testParsesVariablesAsJSON() : void
{ {
$query = '{my query}'; $query = '{my query}';
$variables = ['test' => 1, 'test2' => 2]; $variables = ['test' => 1, 'test2' => 2];
$operation = 'op'; $operation = 'op';
$body = [ $body = [
'query' => $query, 'query' => $query,
'variables' => json_encode($variables), 'variables' => json_encode($variables),
'operationName' => $operation 'operationName' => $operation,
]; ];
$parsed = [ $parsed = [
'raw' => $this->parseRawRequest('application/json', json_encode($body)), 'raw' => $this->parseRawRequest('application/json', json_encode($body)),
'psr' => $this->parsePsrRequest('application/json', json_encode($body)) 'psr' => $this->parsePsrRequest('application/json', json_encode($body)),
]; ];
foreach ($parsed as $method => $parsedBody) { foreach ($parsed as $method => $parsedBody) {
$this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method); $this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method);
@ -136,14 +308,14 @@ class RequestParsingTest extends TestCase
public function testIgnoresInvalidVariablesJson() : void public function testIgnoresInvalidVariablesJson() : void
{ {
$query = '{my query}'; $query = '{my query}';
$variables = '"some invalid json'; $variables = '"some invalid json';
$operation = 'op'; $operation = 'op';
$body = [ $body = [
'query' => $query, 'query' => $query,
'variables' => $variables, 'variables' => $variables,
'operationName' => $operation 'operationName' => $operation,
]; ];
$parsed = [ $parsed = [
'raw' => $this->parseRawRequest('application/json', json_encode($body)), 'raw' => $this->parseRawRequest('application/json', json_encode($body)),
@ -157,27 +329,41 @@ class RequestParsingTest extends TestCase
public function testParsesBatchJSONRequest() : void public function testParsesBatchJSONRequest() : void
{ {
$body = [ $body = [
[ [
'query' => '{my query}', 'query' => '{my query}',
'variables' => ['test' => 1, 'test2' => 2], 'variables' => ['test' => 1, 'test2' => 2],
'operationName' => 'op' 'operationName' => 'op',
], ],
[ [
'queryId' => 'my-query-id', 'queryId' => 'my-query-id',
'variables' => ['test' => 1, 'test2' => 2], 'variables' => ['test' => 1, 'test2' => 2],
'operationName' => 'op2' 'operationName' => 'op2',
], ],
]; ];
$parsed = [ $parsed = [
'raw' => $this->parseRawRequest('application/json', json_encode($body)), 'raw' => $this->parseRawRequest('application/json', json_encode($body)),
'psr' => $this->parsePsrRequest('application/json', json_encode($body)) 'psr' => $this->parsePsrRequest('application/json', json_encode($body)),
]; ];
foreach ($parsed as $method => $parsedBody) { foreach ($parsed as $method => $parsedBody) {
$this->assertInternalType('array', $parsedBody, $method); $this->assertInternalType('array', $parsedBody, $method);
$this->assertCount(2, $parsedBody, $method); $this->assertCount(2, $parsedBody, $method);
$this->assertValidOperationParams($parsedBody[0], $body[0]['query'], null, $body[0]['variables'], $body[0]['operationName'], $method); $this->assertValidOperationParams(
$this->assertValidOperationParams($parsedBody[1], null, $body[1]['queryId'], $body[1]['variables'], $body[1]['operationName'], $method); $parsedBody[0],
$body[0]['query'],
null,
$body[0]['variables'],
$body[0]['operationName'],
$method
);
$this->assertValidOperationParams(
$parsedBody[1],
null,
$body[1]['queryId'],
$body[1]['variables'],
$body[1]['operationName'],
$method
);
} }
} }
@ -187,8 +373,8 @@ class RequestParsingTest extends TestCase
$this->expectException(RequestError::class); $this->expectException(RequestError::class);
$this->expectExceptionMessage('Could not parse JSON: Syntax error'); $this->expectExceptionMessage('Could not parse JSON: Syntax error');
$this->parseRawRequest('application/json', $body); $this->parseRawRequest('application/json', $body);
} }
public function testFailsParsingInvalidRawJsonRequestPsr() : void public function testFailsParsingInvalidRawJsonRequestPsr() : void
{ {
@ -196,7 +382,7 @@ class RequestParsingTest extends TestCase
$this->expectException(InvariantViolation::class); $this->expectException(InvariantViolation::class);
$this->expectExceptionMessage('PSR-7 request is expected to provide parsed body for "application/json" requests but got null'); $this->expectExceptionMessage('PSR-7 request is expected to provide parsed body for "application/json" requests but got null');
$this->parsePsrRequest('application/json', $body); $this->parsePsrRequest('application/json', $body);
} }
public function testFailsParsingNonPreParsedPsrRequest() : void public function testFailsParsingNonPreParsedPsrRequest() : void
@ -222,8 +408,8 @@ class RequestParsingTest extends TestCase
$this->expectException(RequestError::class); $this->expectException(RequestError::class);
$this->expectExceptionMessage('GraphQL Server expects JSON object or array, but got "str"'); $this->expectExceptionMessage('GraphQL Server expects JSON object or array, but got "str"');
$this->parseRawRequest('application/json', $body); $this->parseRawRequest('application/json', $body);
} }
public function testFailsParsingNonArrayOrObjectJsonRequestPsr() : void public function testFailsParsingNonArrayOrObjectJsonRequestPsr() : void
{ {
@ -231,13 +417,13 @@ class RequestParsingTest extends TestCase
$this->expectException(RequestError::class); $this->expectException(RequestError::class);
$this->expectExceptionMessage('GraphQL Server expects JSON object or array, but got "str"'); $this->expectExceptionMessage('GraphQL Server expects JSON object or array, but got "str"');
$this->parsePsrRequest('application/json', $body); $this->parsePsrRequest('application/json', $body);
} }
public function testFailsParsingInvalidContentTypeRaw() : void public function testFailsParsingInvalidContentTypeRaw() : void
{ {
$contentType = 'not-supported-content-type'; $contentType = 'not-supported-content-type';
$body = 'test'; $body = 'test';
$this->expectException(RequestError::class); $this->expectException(RequestError::class);
$this->expectExceptionMessage('Unexpected content type: "not-supported-content-type"'); $this->expectExceptionMessage('Unexpected content type: "not-supported-content-type"');
@ -247,194 +433,38 @@ class RequestParsingTest extends TestCase
public function testFailsParsingInvalidContentTypePsr() : void public function testFailsParsingInvalidContentTypePsr() : void
{ {
$contentType = 'not-supported-content-type'; $contentType = 'not-supported-content-type';
$body = 'test'; $body = 'test';
$this->expectException(RequestError::class); $this->expectException(RequestError::class);
$this->expectExceptionMessage('Unexpected content type: "not-supported-content-type"'); $this->expectExceptionMessage('Unexpected content type: "not-supported-content-type"');
$this->parseRawRequest($contentType, $body); $this->parseRawRequest($contentType, $body);
} }
public function testFailsWithMissingContentTypeRaw() : void public function testFailsWithMissingContentTypeRaw() : void
{ {
$this->expectException(RequestError::class); $this->expectException(RequestError::class);
$this->expectExceptionMessage('Missing "Content-Type" header'); $this->expectExceptionMessage('Missing "Content-Type" header');
$this->parseRawRequest(null, 'test'); $this->parseRawRequest(null, 'test');
} }
public function testFailsWithMissingContentTypePsr() : void public function testFailsWithMissingContentTypePsr() : void
{ {
$this->expectException(RequestError::class); $this->expectException(RequestError::class);
$this->expectExceptionMessage('Missing "Content-Type" header'); $this->expectExceptionMessage('Missing "Content-Type" header');
$this->parsePsrRequest(null, 'test'); $this->parsePsrRequest(null, 'test');
} }
public function testFailsOnMethodsOtherThanPostOrGetRaw() : void public function testFailsOnMethodsOtherThanPostOrGetRaw() : void
{ {
$this->expectException(RequestError::class); $this->expectException(RequestError::class);
$this->expectExceptionMessage('HTTP Method "PUT" is not supported'); $this->expectExceptionMessage('HTTP Method "PUT" is not supported');
$this->parseRawRequest('application/json', json_encode([]), "PUT"); $this->parseRawRequest('application/json', json_encode([]), 'PUT');
} }
public function testFailsOnMethodsOtherThanPostOrGetPsr() : void public function testFailsOnMethodsOtherThanPostOrGetPsr() : void
{ {
$this->expectException(RequestError::class); $this->expectException(RequestError::class);
$this->expectExceptionMessage('HTTP Method "PUT" is not supported'); $this->expectExceptionMessage('HTTP Method "PUT" is not supported');
$this->parsePsrRequest('application/json', json_encode([]), "PUT"); $this->parsePsrRequest('application/json', json_encode([]), 'PUT');
}
/**
* @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();
return $helper->parseHttpRequest(function() use ($content) {
return $content;
});
}
/**
* @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);
}
/**
* @param array $postValue
* @return OperationParams|OperationParams[]
*/
private function parseRawFormUrlencodedRequest($postValue)
{
$_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST = $postValue;
$helper = new Helper();
return $helper->parseHttpRequest(function() {
throw new InvariantViolation("Shouldn't read from php://input for urlencoded request");
});
}
/**
* @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);
}
/**
* @param array $postValue
* @return OperationParams|OperationParams[]
*/
private function parseRawMultipartFormDataRequest($postValue)
{
$_SERVER['CONTENT_TYPE'] = 'multipart/form-data; boundary=----FormBoundary';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST = $postValue;
$helper = new Helper();
return $helper->parseHttpRequest(function() {
throw new InvariantViolation("Shouldn't read from php://input for multipart/form-data request");
});
}
/**
* @param $postValue
* @return array|Helper
*/
private function parsePsrMultipartFormDataRequest($postValue)
{
$psrRequest = new PsrRequestStub();
$psrRequest->headers['content-type'] = ['multipart/form-data; boundary=----FormBoundary'];
$psrRequest->method = 'POST';
$psrRequest->parsedBody = $postValue;
$helper = new Helper();
return $helper->parsePsrRequest($psrRequest);
}
/**
* @param $getValue
* @return OperationParams
*/
private function parseRawGetRequest($getValue)
{
$_SERVER['REQUEST_METHOD'] = 'GET';
$_GET = $getValue;
$helper = new Helper();
return $helper->parseHttpRequest(function() {
throw new InvariantViolation("Shouldn't read from php://input for urlencoded request");
});
}
/**
* @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);
}
/**
* @param OperationParams $params
* @param string $query
* @param string $queryId
* @param array $variables
* @param string $operation
*/
private function assertValidOperationParams($params, $query, $queryId = null, $variables = null, $operation = null, $message = '')
{
$this->assertInstanceOf(OperationParams::class, $params, $message);
$this->assertSame($query, $params->query, $message);
$this->assertSame($queryId, $params->queryId, $message);
$this->assertSame($variables, $params->variables, $message);
$this->assertSame($operation, $params->operation, $message);
} }
} }

View File

@ -1,4 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace GraphQL\Tests\Server; namespace GraphQL\Tests\Server;
use GraphQL\Server\Helper; use GraphQL\Server\Helper;
@ -9,28 +12,35 @@ class RequestValidationTest extends TestCase
{ {
public function testSimpleRequestShouldValidate() : void public function testSimpleRequestShouldValidate() : void
{ {
$query = '{my q}'; $query = '{my q}';
$variables = ['a' => 'b', 'c' => 'd']; $variables = ['a' => 'b', 'c' => 'd'];
$operation = 'op'; $operation = 'op';
$parsedBody = OperationParams::create([ $parsedBody = OperationParams::create([
'query' => $query, 'query' => $query,
'variables' => $variables, 'variables' => $variables,
'operationName' => $operation, 'operationName' => $operation,
]); ]);
$this->assertValid($parsedBody); $this->assertValid($parsedBody);
} }
private function assertValid($parsedRequest)
{
$helper = new Helper();
$errors = $helper->validateOperationParams($parsedRequest);
$this->assertEmpty($errors, isset($errors[0]) ? $errors[0]->getMessage() : '');
}
public function testRequestWithQueryIdShouldValidate() : void public function testRequestWithQueryIdShouldValidate() : void
{ {
$queryId = 'some-query-id'; $queryId = 'some-query-id';
$variables = ['a' => 'b', 'c' => 'd']; $variables = ['a' => 'b', 'c' => 'd'];
$operation = 'op'; $operation = 'op';
$parsedBody = OperationParams::create([ $parsedBody = OperationParams::create([
'queryId' => $queryId, 'queryId' => $queryId,
'variables' => $variables, 'variables' => $variables,
'operationName' => $operation, 'operationName' => $operation,
]); ]);
@ -40,7 +50,7 @@ class RequestValidationTest extends TestCase
public function testRequiresQueryOrQueryId() : void public function testRequiresQueryOrQueryId() : void
{ {
$parsedBody = OperationParams::create([ $parsedBody = OperationParams::create([
'variables' => ['foo' => 'bar'], 'variables' => ['foo' => 'bar'],
'operationName' => 'op', 'operationName' => 'op',
]); ]);
@ -50,10 +60,21 @@ class RequestValidationTest extends TestCase
); );
} }
private function assertInputError($parsedRequest, $expectedMessage)
{
$helper = new Helper();
$errors = $helper->validateOperationParams($parsedRequest);
if (! empty($errors[0])) {
$this->assertEquals($expectedMessage, $errors[0]->getMessage());
} else {
$this->fail('Expected error not returned');
}
}
public function testFailsWhenBothQueryAndQueryIdArePresent() : void public function testFailsWhenBothQueryAndQueryIdArePresent() : void
{ {
$parsedBody = OperationParams::create([ $parsedBody = OperationParams::create([
'query' => '{my query}', 'query' => '{my query}',
'queryId' => 'my-query-id', 'queryId' => 'my-query-id',
]); ]);
@ -66,7 +87,7 @@ class RequestValidationTest extends TestCase
public function testFailsWhenQueryParameterIsNotString() : void public function testFailsWhenQueryParameterIsNotString() : void
{ {
$parsedBody = OperationParams::create([ $parsedBody = OperationParams::create([
'query' => ['t' => '{my query}'] 'query' => ['t' => '{my query}'],
]); ]);
$this->assertInputError( $this->assertInputError(
@ -78,7 +99,7 @@ class RequestValidationTest extends TestCase
public function testFailsWhenQueryIdParameterIsNotString() : void public function testFailsWhenQueryIdParameterIsNotString() : void
{ {
$parsedBody = OperationParams::create([ $parsedBody = OperationParams::create([
'queryId' => ['t' => '{my query}'] 'queryId' => ['t' => '{my query}'],
]); ]);
$this->assertInputError( $this->assertInputError(
@ -90,8 +111,8 @@ class RequestValidationTest extends TestCase
public function testFailsWhenOperationParameterIsNotString() : void public function testFailsWhenOperationParameterIsNotString() : void
{ {
$parsedBody = OperationParams::create([ $parsedBody = OperationParams::create([
'query' => '{my query}', 'query' => '{my query}',
'operationName' => [] 'operationName' => [],
]); ]);
$this->assertInputError( $this->assertInputError(
@ -105,17 +126,17 @@ class RequestValidationTest extends TestCase
*/ */
public function testIgnoresNullAndEmptyStringVariables() : void public function testIgnoresNullAndEmptyStringVariables() : void
{ {
$query = '{my q}'; $query = '{my q}';
$parsedBody = OperationParams::create([ $parsedBody = OperationParams::create([
'query' => $query, 'query' => $query,
'variables' => null 'variables' => null,
]); ]);
$this->assertValid($parsedBody); $this->assertValid($parsedBody);
$variables = ""; $variables = '';
$parsedBody = OperationParams::create([ $parsedBody = OperationParams::create([
'query' => $query, 'query' => $query,
'variables' => $variables 'variables' => $variables,
]); ]);
$this->assertValid($parsedBody); $this->assertValid($parsedBody);
} }
@ -123,8 +144,8 @@ class RequestValidationTest extends TestCase
public function testFailsWhenVariablesParameterIsNotObject() : void public function testFailsWhenVariablesParameterIsNotObject() : void
{ {
$parsedBody = OperationParams::create([ $parsedBody = OperationParams::create([
'query' => '{my query}', 'query' => '{my query}',
'variables' => 0 'variables' => 0,
]); ]);
$this->assertInputError( $this->assertInputError(
@ -132,22 +153,4 @@ class RequestValidationTest extends TestCase
'GraphQL Request parameter "variables" must be object or JSON string parsed to object, but got 0' 'GraphQL Request parameter "variables" must be object or JSON string parsed to object, but got 0'
); );
} }
private function assertValid($parsedRequest)
{
$helper = new Helper();
$errors = $helper->validateOperationParams($parsedRequest);
$this->assertEmpty($errors, isset($errors[0]) ? $errors[0]->getMessage() : '');
}
private function assertInputError($parsedRequest, $expectedMessage)
{
$helper = new Helper();
$errors = $helper->validateOperationParams($parsedRequest);
if (!empty($errors[0])) {
$this->assertEquals($expectedMessage, $errors[0]->getMessage());
} else {
$this->fail('Expected error not returned');
}
}
} }

View File

@ -1,12 +1,15 @@
<?php <?php
declare(strict_types=1);
namespace GraphQL\Tests\Server; namespace GraphQL\Tests\Server;
use GraphQL\Error\InvariantViolation; use GraphQL\Error\InvariantViolation;
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter; use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
use GraphQL\Type\Schema;
use GraphQL\Server\ServerConfig; use GraphQL\Server\ServerConfig;
use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type; use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
class ServerConfigTest extends TestCase class ServerConfigTest extends TestCase
@ -70,7 +73,8 @@ class ServerConfigTest extends TestCase
{ {
$config = ServerConfig::create(); $config = ServerConfig::create();
$formatter = function() {}; $formatter = function () {
};
$config->setErrorFormatter($formatter); $config->setErrorFormatter($formatter);
$this->assertSame($formatter, $config->getErrorFormatter()); $this->assertSame($formatter, $config->getErrorFormatter());
@ -83,7 +87,8 @@ class ServerConfigTest extends TestCase
{ {
$config = ServerConfig::create(); $config = ServerConfig::create();
$handler = function() {}; $handler = function () {
};
$config->setErrorsHandler($handler); $config->setErrorsHandler($handler);
$this->assertSame($handler, $config->getErrorsHandler()); $this->assertSame($handler, $config->getErrorsHandler());
@ -113,11 +118,17 @@ class ServerConfigTest extends TestCase
$config->setValidationRules($rules); $config->setValidationRules($rules);
$this->assertSame($rules, $config->getValidationRules()); $this->assertSame($rules, $config->getValidationRules());
$rules = [function() {}]; $rules = [function () {
},
];
$config->setValidationRules($rules); $config->setValidationRules($rules);
$this->assertSame($rules, $config->getValidationRules()); $this->assertSame($rules, $config->getValidationRules());
$rules = function() {return [function() {}];}; $rules = function () {
return [function () {
},
];
};
$config->setValidationRules($rules); $config->setValidationRules($rules);
$this->assertSame($rules, $config->getValidationRules()); $this->assertSame($rules, $config->getValidationRules());
} }
@ -126,7 +137,8 @@ class ServerConfigTest extends TestCase
{ {
$config = ServerConfig::create(); $config = ServerConfig::create();
$resolver = function() {}; $resolver = function () {
};
$config->setFieldResolver($resolver); $config->setFieldResolver($resolver);
$this->assertSame($resolver, $config->getFieldResolver()); $this->assertSame($resolver, $config->getFieldResolver());
@ -139,7 +151,8 @@ class ServerConfigTest extends TestCase
{ {
$config = ServerConfig::create(); $config = ServerConfig::create();
$loader = function() {}; $loader = function () {
};
$config->setPersistentQueryLoader($loader); $config->setPersistentQueryLoader($loader);
$this->assertSame($loader, $config->getPersistentQueryLoader()); $this->assertSame($loader, $config->getPersistentQueryLoader());
@ -162,18 +175,23 @@ class ServerConfigTest extends TestCase
public function testAcceptsArray() : void public function testAcceptsArray() : void
{ {
$arr = [ $arr = [
'schema' => new \GraphQL\Type\Schema([ 'schema' => new Schema([
'query' => new ObjectType(['name' => 't', 'fields' => ['a' => Type::string()]]) 'query' => new ObjectType(['name' => 't', 'fields' => ['a' => Type::string()]]),
]), ]),
'context' => new \stdClass(), 'context' => new \stdClass(),
'rootValue' => new \stdClass(), 'rootValue' => new \stdClass(),
'errorFormatter' => function() {}, 'errorFormatter' => function () {
'promiseAdapter' => new SyncPromiseAdapter(), },
'validationRules' => [function() {}], 'promiseAdapter' => new SyncPromiseAdapter(),
'fieldResolver' => function() {}, 'validationRules' => [function () {
'persistentQueryLoader' => function() {}, },
'debug' => true, ],
'queryBatching' => true, 'fieldResolver' => function () {
},
'persistentQueryLoader' => function () {
},
'debug' => true,
'queryBatching' => true,
]; ];
$config = ServerConfig::create($arr); $config = ServerConfig::create($arr);
@ -192,9 +210,7 @@ class ServerConfigTest extends TestCase
public function testThrowsOnInvalidArrayKey() : void public function testThrowsOnInvalidArrayKey() : void
{ {
$arr = [ $arr = ['missingKey' => 'value'];
'missingKey' => 'value'
];
$this->expectException(InvariantViolation::class); $this->expectException(InvariantViolation::class);
$this->expectExceptionMessage('Unknown server config option "missingKey"'); $this->expectExceptionMessage('Unknown server config option "missingKey"');
@ -204,7 +220,7 @@ class ServerConfigTest extends TestCase
public function testInvalidValidationRules() : void public function testInvalidValidationRules() : void
{ {
$rules = new \stdClass(); $rules = new \stdClass();
$config = ServerConfig::create(); $config = ServerConfig::create();
$this->expectException(InvariantViolation::class); $this->expectException(InvariantViolation::class);

View File

@ -1,6 +1,8 @@
<?php <?php
namespace GraphQL\Tests\Server;
declare(strict_types=1);
namespace GraphQL\Tests\Server;
use GraphQL\Deferred; use GraphQL\Deferred;
use GraphQL\Error\UserError; use GraphQL\Error\UserError;
@ -8,87 +10,94 @@ use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type; use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema; use GraphQL\Type\Schema;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use function trigger_error;
use const E_USER_DEPRECATED;
use const E_USER_NOTICE;
use const E_USER_WARNING;
abstract class ServerTestCase extends TestCase abstract class ServerTestCase extends TestCase
{ {
protected function buildSchema() protected function buildSchema()
{ {
$schema = new Schema([ $schema = new Schema([
'query' => new ObjectType([ 'query' => new ObjectType([
'name' => 'Query', 'name' => 'Query',
'fields' => [ 'fields' => [
'f1' => [ 'f1' => [
'type' => Type::string(), 'type' => Type::string(),
'resolve' => function($root, $args, $context, $info) { 'resolve' => function ($root, $args, $context, $info) {
return $info->fieldName; return $info->fieldName;
} },
], ],
'fieldWithPhpError' => [ 'fieldWithPhpError' => [
'type' => Type::string(), 'type' => Type::string(),
'resolve' => function($root, $args, $context, $info) { 'resolve' => function ($root, $args, $context, $info) {
trigger_error('deprecated', E_USER_DEPRECATED); trigger_error('deprecated', E_USER_DEPRECATED);
trigger_error('notice', E_USER_NOTICE); trigger_error('notice', E_USER_NOTICE);
trigger_error('warning', E_USER_WARNING); trigger_error('warning', E_USER_WARNING);
$a = []; $a = [];
$a['test']; // should produce PHP notice $a['test']; // should produce PHP notice
return $info->fieldName; return $info->fieldName;
} },
], ],
'fieldWithException' => [ 'fieldWithException' => [
'type' => Type::string(), 'type' => Type::string(),
'resolve' => function($root, $args, $context, $info) { 'resolve' => function ($root, $args, $context, $info) {
throw new UserError("This is the exception we want"); throw new UserError('This is the exception we want');
} },
], ],
'testContextAndRootValue' => [ 'testContextAndRootValue' => [
'type' => Type::string(), 'type' => Type::string(),
'resolve' => function($root, $args, $context, $info) { 'resolve' => function ($root, $args, $context, $info) {
$context->testedRootValue = $root; $context->testedRootValue = $root;
return $info->fieldName; return $info->fieldName;
} },
], ],
'fieldWithArg' => [ 'fieldWithArg' => [
'type' => Type::string(), 'type' => Type::string(),
'args' => [ 'args' => [
'arg' => [ 'arg' => [
'type' => Type::nonNull(Type::string()) 'type' => Type::nonNull(Type::string()),
], ],
], ],
'resolve' => function($root, $args) { 'resolve' => function ($root, $args) {
return $args['arg']; return $args['arg'];
} },
], ],
'dfd' => [ 'dfd' => [
'type' => Type::string(), 'type' => Type::string(),
'args' => [ 'args' => [
'num' => [ 'num' => [
'type' => Type::nonNull(Type::int()) 'type' => Type::nonNull(Type::int()),
], ],
], ],
'resolve' => function($root, $args, $context) { 'resolve' => function ($root, $args, $context) {
$context['buffer']($args['num']); $context['buffer']($args['num']);
return new Deferred(function() use ($args, $context) { return new Deferred(function () use ($args, $context) {
return $context['load']($args['num']); return $context['load']($args['num']);
}); });
} },
] ],
] ],
]), ]),
'mutation' => new ObjectType([ 'mutation' => new ObjectType([
'name' => 'Mutation', 'name' => 'Mutation',
'fields' => [ 'fields' => [
'm1' => [ 'm1' => [
'type' => new ObjectType([ 'type' => new ObjectType([
'name' => 'TestMutation', 'name' => 'TestMutation',
'fields' => [ 'fields' => [
'result' => Type::string() 'result' => Type::string(),
] ],
]) ]),
] ],
] ],
]) ]),
]); ]);
return $schema; return $schema;
} }
} }

View File

@ -1,4 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace GraphQL\Tests\Server; namespace GraphQL\Tests\Server;
use GraphQL\Executor\ExecutionResult; use GraphQL\Executor\ExecutionResult;
@ -6,72 +9,75 @@ use GraphQL\Server\Helper;
use GraphQL\Server\ServerConfig; use GraphQL\Server\ServerConfig;
use GraphQL\Server\StandardServer; use GraphQL\Server\StandardServer;
use GraphQL\Tests\Server\Psr7\PsrRequestStub; use GraphQL\Tests\Server\Psr7\PsrRequestStub;
use GraphQL\Tests\Server\Psr7\PsrStreamStub; use function json_encode;
class StandardServerTest extends ServerTestCase class StandardServerTest extends ServerTestCase
{ {
/** /** @var ServerConfig */
* @var ServerConfig
*/
private $config; private $config;
public function setUp() public function setUp()
{ {
$schema = $this->buildSchema(); $schema = $this->buildSchema();
$this->config = ServerConfig::create() $this->config = ServerConfig::create()
->setSchema($schema); ->setSchema($schema);
} }
public function testSimpleRequestExecutionWithOutsideParsing() : void public function testSimpleRequestExecutionWithOutsideParsing() : void
{ {
$body = json_encode([ $body = json_encode(['query' => '{f1}']);
'query' => '{f1}'
]);
$parsedBody = $this->parseRawRequest('application/json', $body); $parsedBody = $this->parseRawRequest('application/json', $body);
$server = new StandardServer($this->config); $server = new StandardServer($this->config);
$result = $server->executeRequest($parsedBody); $result = $server->executeRequest($parsedBody);
$expected = [ $expected = [
'data' => [ 'data' => ['f1' => 'f1'],
'f1' => 'f1',
]
]; ];
$this->assertEquals($expected, $result->toArray(true)); $this->assertEquals($expected, $result->toArray(true));
} }
private function parseRawRequest($contentType, $content, $method = 'POST')
{
$_SERVER['CONTENT_TYPE'] = $contentType;
$_SERVER['REQUEST_METHOD'] = $method;
$helper = new Helper();
return $helper->parseHttpRequest(function () use ($content) {
return $content;
});
}
public function testSimplePsrRequestExecution() : void public function testSimplePsrRequestExecution() : void
{ {
$body = [ $body = ['query' => '{f1}'];
'query' => '{f1}'
];
$expected = [ $expected = [
'data' => [ 'data' => ['f1' => 'f1'],
'f1' => 'f1'
]
]; ];
$request = $this->preparePsrRequest('application/json', $body); $request = $this->preparePsrRequest('application/json', $body);
$this->assertPsrRequestEquals($expected, $request); $this->assertPsrRequestEquals($expected, $request);
} }
public function testMultipleOperationPsrRequestExecution() : void private function preparePsrRequest($contentType, $parsedBody)
{ {
$body = [ $psrRequest = new PsrRequestStub();
'query' => 'query firstOp {fieldWithPhpError} query secondOp {f1}', $psrRequest->headers['content-type'] = [$contentType];
'operationName' => 'secondOp' $psrRequest->method = 'POST';
]; $psrRequest->parsedBody = $parsedBody;
$expected = [ return $psrRequest;
'data' => [ }
'f1' => 'f1'
]
];
$request = $this->preparePsrRequest('application/json', $body); private function assertPsrRequestEquals($expected, $request)
$this->assertPsrRequestEquals($expected, $request); {
$result = $this->executePsrRequest($request);
$this->assertArraySubset($expected, $result->toArray(true));
return $result;
} }
private function executePsrRequest($psrRequest) private function executePsrRequest($psrRequest)
@ -79,33 +85,22 @@ class StandardServerTest extends ServerTestCase
$server = new StandardServer($this->config); $server = new StandardServer($this->config);
$result = $server->executePsrRequest($psrRequest); $result = $server->executePsrRequest($psrRequest);
$this->assertInstanceOf(ExecutionResult::class, $result); $this->assertInstanceOf(ExecutionResult::class, $result);
return $result; return $result;
} }
private function assertPsrRequestEquals($expected, $request) public function testMultipleOperationPsrRequestExecution() : void
{ {
$result = $this->executePsrRequest($request); $body = [
$this->assertArraySubset($expected, $result->toArray(true)); 'query' => 'query firstOp {fieldWithPhpError} query secondOp {f1}',
return $result; 'operationName' => 'secondOp',
} ];
private function preparePsrRequest($contentType, $parsedBody) $expected = [
{ 'data' => ['f1' => 'f1'],
$psrRequest = new PsrRequestStub(); ];
$psrRequest->headers['content-type'] = [$contentType];
$psrRequest->method = 'POST';
$psrRequest->parsedBody = $parsedBody;
return $psrRequest;
}
private function parseRawRequest($contentType, $content, $method = 'POST') $request = $this->preparePsrRequest('application/json', $body);
{ $this->assertPsrRequestEquals($expected, $request);
$_SERVER['CONTENT_TYPE'] = $contentType;
$_SERVER['REQUEST_METHOD'] = $method;
$helper = new Helper();
return $helper->parseHttpRequest(function() use ($content) {
return $content;
});
} }
} }