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
declare(strict_types=1);
namespace GraphQL\Tests\Server\Psr7;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;
use function strtolower;
class PsrRequestStub implements ServerRequestInterface
{
@ -13,14 +17,10 @@ class PsrRequestStub implements ServerRequestInterface
public $method;
/**
* @var PsrStreamStub
*/
/** @var PsrStreamStub */
public $body;
/**
* @var array
*/
/** @var mixed[] */
public $parsedBody;
/**
@ -32,7 +32,7 @@ class PsrRequestStub implements ServerRequestInterface
*/
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)
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -80,7 +80,7 @@ class PsrRequestStub implements ServerRequestInterface
*/
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)
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -113,7 +113,8 @@ class PsrRequestStub implements ServerRequestInterface
public function getHeader($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)
{
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
* 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).
* @return static
* @throws \InvalidArgumentException for invalid header names or values.
*/
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
* 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).
* @return static
* @throws \InvalidArgumentException for invalid header names or values.
*/
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)
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -223,7 +224,7 @@ class PsrRequestStub implements ServerRequestInterface
*/
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()
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -266,7 +267,7 @@ class PsrRequestStub implements ServerRequestInterface
*/
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)
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -339,13 +340,13 @@ class PsrRequestStub implements ServerRequestInterface
* new UriInterface instance.
*
* @link http://tools.ietf.org/html/rfc3986#section-4.3
* @param UriInterface $uri New request URI to use.
* @param bool $preserveHost Preserve the original state of the Host header.
* @param UriInterface $uri New request URI to use.
* @param bool $preserveHost Preserve the original state of the Host header.
* @return static
*/
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()
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -374,7 +375,7 @@ class PsrRequestStub implements ServerRequestInterface
*/
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)
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -440,7 +441,7 @@ class PsrRequestStub implements ServerRequestInterface
*/
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()
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -473,7 +474,7 @@ class PsrRequestStub implements ServerRequestInterface
*/
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)
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -542,7 +543,7 @@ class PsrRequestStub implements ServerRequestInterface
*/
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.
*
* @see getAttributes()
* @param string $name The attribute name.
* @param mixed $default Default value to return if the attribute does not exist.
* @param string $name The attribute name.
* @param mixed $default Default value to return if the attribute does not exist.
* @return mixed
*/
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.
*
* @see getAttributes()
* @param string $name The attribute name.
* @param mixed $value The value of the attribute.
* @param string $name The attribute name.
* @param mixed $value The value of the attribute.
* @return static
*/
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)
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
}

View File

@ -1,6 +1,8 @@
<?php
namespace GraphQL\Tests\Server\Psr7;
declare(strict_types=1);
namespace GraphQL\Tests\Server\Psr7;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
@ -22,7 +24,7 @@ class PsrResponseStub implements ResponseInterface
*/
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)
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -70,7 +72,7 @@ class PsrResponseStub implements ResponseInterface
*/
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)
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -102,7 +104,7 @@ class PsrResponseStub implements ResponseInterface
*/
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)
{
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
* 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).
* @return static
* @throws \InvalidArgumentException for invalid header names or values.
*/
public function withHeader($name, $value)
{
$tmp = clone $this;
$tmp = clone $this;
$tmp->headers[$name][] = $value;
return $tmp;
}
@ -162,14 +165,14 @@ class PsrResponseStub implements ResponseInterface
* immutability of the message, and MUST return an instance that has the
* 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).
* @return static
* @throws \InvalidArgumentException for invalid header names or values.
*/
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)
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
/**
@ -196,7 +199,7 @@ class PsrResponseStub implements ResponseInterface
*/
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)
{
$tmp = clone $this;
$tmp = clone $this;
$tmp->body = $body;
return $tmp;
}
@ -229,7 +233,7 @@ class PsrResponseStub implements ResponseInterface
*/
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://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
* provided status code; if none is provided, implementations MAY
* use the defaults as suggested in the HTTP specification.
@ -254,8 +258,9 @@ class PsrResponseStub implements ResponseInterface
*/
public function withStatus($code, $reasonPhrase = '')
{
$tmp = clone $this;
$tmp = clone $this;
$tmp->statusCode = $code;
return $tmp;
}
@ -274,6 +279,6 @@ class PsrResponseStub implements ResponseInterface
*/
public function getReasonPhrase()
{
throw new \Exception("Not implemented");
throw new \Exception('Not implemented');
}
}
}

View File

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

View File

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

View File

@ -1,11 +1,12 @@
<?php
declare(strict_types=1);
namespace GraphQL\Tests\Server;
use GraphQL\Deferred;
use GraphQL\Error\Debug;
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation;
use GraphQL\Error\UserError;
use GraphQL\Executor\ExecutionResult;
use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\Parser;
@ -16,17 +17,17 @@ use GraphQL\Server\ServerConfig;
use GraphQL\Validator\DocumentValidator;
use GraphQL\Validator\Rules\CustomValidationRule;
use GraphQL\Validator\ValidationContext;
use function count;
use function sprintf;
class QueryExecutionTest extends ServerTestCase
{
/**
* @var ServerConfig
*/
/** @var ServerConfig */
private $config;
public function setUp()
{
$schema = $this->buildSchema();
$schema = $this->buildSchema();
$this->config = ServerConfig::create()
->setSchema($schema);
}
@ -36,14 +37,30 @@ class QueryExecutionTest extends ServerTestCase
$query = '{f1}';
$expected = [
'data' => [
'f1' => 'f1'
]
'data' => ['f1' => 'f1'],
];
$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
{
$query = '{f1';
@ -70,17 +87,17 @@ class QueryExecutionTest extends ServerTestCase
';
$expected = [
'data' => [
'data' => [
'fieldWithException' => null,
'f1' => 'f1'
'f1' => 'f1',
],
'errors' => [
[
'message' => 'This is the exception we want',
'path' => ['fieldWithException'],
'trace' => []
]
]
'path' => ['fieldWithException'],
'trace' => [],
],
],
];
$result = $this->executeQuery($query)->toArray();
@ -90,7 +107,7 @@ class QueryExecutionTest extends ServerTestCase
public function testPassesRootValueAndContext() : void
{
$rootValue = 'myRootValue';
$context = new \stdClass();
$context = new \stdClass();
$this->config
->setContext($context)
@ -102,7 +119,7 @@ class QueryExecutionTest extends ServerTestCase
}
';
$this->assertTrue(!isset($context->testedRootValue));
$this->assertTrue(! isset($context->testedRootValue));
$this->executeQuery($query);
$this->assertSame($rootValue, $context->testedRootValue);
}
@ -110,30 +127,30 @@ class QueryExecutionTest extends ServerTestCase
public function testPassesVariables() : void
{
$variables = ['a' => 'a', 'b' => 'b'];
$query = '
$query = '
query ($a: String!, $b: String!) {
a: fieldWithArg(arg: $a)
b: fieldWithArg(arg: $b)
}
';
$expected = [
$expected = [
'data' => [
'a' => 'a',
'b' => 'b'
]
'b' => 'b',
],
];
$this->assertQueryResultEquals($expected, $query, $variables);
}
public function testPassesCustomValidationRules() : void
{
$query = '
$query = '
{nonExistentField}
';
$expected = [
'errors' => [
['message' => 'Cannot query field "nonExistentField" on type "Query".']
]
['message' => 'Cannot query field "nonExistentField" on type "Query".'],
],
];
$this->assertQueryResultEquals($expected, $query);
@ -141,15 +158,16 @@ class QueryExecutionTest extends ServerTestCase
$called = false;
$rules = [
new CustomValidationRule('SomeRule', function() use (&$called) {
new CustomValidationRule('SomeRule', function () use (&$called) {
$called = true;
return [];
})
}),
];
$this->config->setValidationRules($rules);
$expected = [
'data' => []
'data' => [],
];
$this->assertQueryResultEquals($expected, $query);
$this->assertTrue($called);
@ -160,11 +178,12 @@ class QueryExecutionTest extends ServerTestCase
$called = false;
$params = $doc = $operationType = null;
$this->config->setValidationRules(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
$called = true;
$params = $p;
$doc = $d;
$this->config->setValidationRules(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
$called = true;
$params = $p;
$doc = $d;
$operationType = $o;
return [];
});
@ -178,23 +197,25 @@ class QueryExecutionTest extends ServerTestCase
public function testAllowsDifferentValidationRulesDependingOnOperation() : void
{
$q1 = '{f1}';
$q2 = '{invalid}';
$q1 = '{f1}';
$q2 = '{invalid}';
$called1 = 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) {
$called1 = true;
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']];
@ -202,8 +223,8 @@ class QueryExecutionTest extends ServerTestCase
$this->assertTrue($called1);
$this->assertFalse($called2);
$called1 = false;
$called2 = false;
$called1 = false;
$called2 = false;
$expected = ['errors' => [['message' => 'This is the error we are looking for!']]];
$this->assertQueryResultEquals($expected, $q2);
$this->assertFalse($called1);
@ -213,7 +234,7 @@ class QueryExecutionTest extends ServerTestCase
public function testAllowsSkippingValidation() : void
{
$this->config->setValidationRules([]);
$query = '{nonExistentField}';
$query = '{nonExistentField}';
$expected = ['data' => []];
$this->assertQueryResultEquals($expected, $query);
}
@ -225,23 +246,29 @@ class QueryExecutionTest extends ServerTestCase
$expected = [
'errors' => [
[
'message' => 'Persisted queries are not supported by this server',
'category' => 'request'
]
]
'message' => 'Persisted queries are not supported by this server',
'category' => 'request',
],
],
];
$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
{
$batch = [
[
'query' => '{invalid}'
],
[
'query' => '{f1,fieldWithException}'
]
['query' => '{invalid}'],
['query' => '{f1,fieldWithException}'],
];
$result = $this->executeBatchedQuery($batch);
@ -250,18 +277,18 @@ class QueryExecutionTest extends ServerTestCase
[
'errors' => [
[
'message' => 'Batched queries are not supported by this server',
'category' => 'request'
]
]
'message' => 'Batched queries are not supported by this server',
'category' => 'request',
],
],
],
[
'errors' => [
[
'message' => 'Batched queries are not supported by this server',
'category' => 'request'
]
]
'message' => 'Batched queries are not supported by this server',
'category' => 'request',
],
],
],
];
@ -269,6 +296,31 @@ class QueryExecutionTest extends ServerTestCase
$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
{
$mutation = 'mutation { a }';
@ -276,10 +328,10 @@ class QueryExecutionTest extends ServerTestCase
$expected = [
'errors' => [
[
'message' => 'GET supports only query operation',
'category' => 'request'
]
]
'message' => 'GET supports only query operation',
'category' => 'request',
],
],
];
$result = $this->executeQuery($mutation, null, true);
@ -289,9 +341,10 @@ class QueryExecutionTest extends ServerTestCase
public function testAllowsPersistentQueries() : void
{
$called = false;
$this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) {
$this->config->setPersistentQueryLoader(function ($queryId, OperationParams $params) use (&$called) {
$called = true;
$this->assertEquals('some-id', $queryId);
return '{f1}';
});
@ -299,17 +352,16 @@ class QueryExecutionTest extends ServerTestCase
$this->assertTrue($called);
$expected = [
'data' => [
'f1' => 'f1'
]
'data' => ['f1' => 'f1'],
];
$this->assertEquals($expected, $result->toArray());
// Make sure it allows returning document node:
$called = false;
$this->config->setPersistentQueryLoader(function($queryId, OperationParams $params) use (&$called) {
$this->config->setPersistentQueryLoader(function ($queryId, OperationParams $params) use (&$called) {
$called = true;
$this->assertEquals('some-id', $queryId);
return Parser::parse('{f1}');
});
$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 ' .
'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'];
});
$this->executePersistedQuery('some-id');
@ -332,56 +384,55 @@ class QueryExecutionTest extends ServerTestCase
public function testPersistedQueriesAreStillValidatedByDefault() : void
{
$this->config->setPersistentQueryLoader(function() {
$this->config->setPersistentQueryLoader(function () {
return '{invalid}';
});
$result = $this->executePersistedQuery('some-id');
$result = $this->executePersistedQuery('some-id');
$expected = [
'errors' => [
[
'message' => 'Cannot query field "invalid" on type "Query".',
'locations' => [ ['line' => 1, 'column' => 2] ],
'category' => 'graphql'
]
]
'message' => 'Cannot query field "invalid" on type "Query".',
'locations' => [['line' => 1, 'column' => 2]],
'category' => 'graphql',
],
],
];
$this->assertEquals($expected, $result->toArray());
}
public function testAllowSkippingValidationForPersistedQueries() : void
{
$this->config
->setPersistentQueryLoader(function($queryId) {
->setPersistentQueryLoader(function ($queryId) {
if ($queryId === 'some-id') {
return '{invalid}';
} else {
return '{invalid2}';
}
return '{invalid2}';
})
->setValidationRules(function(OperationParams $params) {
->setValidationRules(function (OperationParams $params) {
if ($params->queryId === 'some-id') {
return [];
} else {
return DocumentValidator::allRules();
}
return DocumentValidator::allRules();
});
$result = $this->executePersistedQuery('some-id');
$result = $this->executePersistedQuery('some-id');
$expected = [
'data' => []
'data' => [],
];
$this->assertEquals($expected, $result->toArray());
$result = $this->executePersistedQuery('some-other-id');
$result = $this->executePersistedQuery('some-other-id');
$expected = [
'errors' => [
[
'message' => 'Cannot query field "invalid2" on type "Query".',
'locations' => [ ['line' => 1, 'column' => 2] ],
'category' => 'graphql'
]
]
'message' => 'Cannot query field "invalid2" on type "Query".',
'locations' => [['line' => 1, 'column' => 2]],
'category' => 'graphql',
],
],
];
$this->assertEquals($expected, $result->toArray());
}
@ -390,7 +441,7 @@ class QueryExecutionTest extends ServerTestCase
{
$this->expectException(InvariantViolation::class);
$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();
});
$this->executeQuery('{f1}');
@ -401,44 +452,40 @@ class QueryExecutionTest extends ServerTestCase
$this->config->setQueryBatching(true);
$batch = [
['query' => '{invalid}'],
['query' => '{f1,fieldWithException}'],
[
'query' => '{invalid}'
],
[
'query' => '{f1,fieldWithException}'
],
[
'query' => '
'query' => '
query ($a: String!, $b: String!) {
a: fieldWithArg(arg: $a)
b: fieldWithArg(arg: $b)
}
',
'variables' => ['a' => 'a', 'b' => 'b'],
]
],
];
$result = $this->executeBatchedQuery($batch);
$expected = [
[
'errors' => [['message' => 'Cannot query field "invalid" on type "Query".']]
'errors' => [['message' => 'Cannot query field "invalid" on type "Query".']],
],
[
'data' => [
'f1' => 'f1',
'fieldWithException' => null
'data' => [
'f1' => 'f1',
'fieldWithException' => null,
],
'errors' => [
['message' => 'This is the exception we want']
]
['message' => 'This is the exception we want'],
],
],
[
'data' => [
'a' => 'a',
'b' => 'b'
]
]
'b' => 'b',
],
],
];
$this->assertArraySubset($expected[0], $result[0]->toArray());
@ -449,15 +496,9 @@ class QueryExecutionTest extends ServerTestCase
public function testDeferredsAreSharedAmongAllBatchedQueries() : void
{
$batch = [
[
'query' => '{dfd(num: 1)}'
],
[
'query' => '{dfd(num: 2)}'
],
[
'query' => '{dfd(num: 3)}',
]
['query' => '{dfd(num: 1)}'],
['query' => '{dfd(num: 2)}'],
['query' => '{dfd(num: 3)}'],
];
$calls = [];
@ -466,13 +507,14 @@ class QueryExecutionTest extends ServerTestCase
->setQueryBatching(true)
->setRootValue('1')
->setContext([
'buffer' => function($num) use (&$calls) {
$calls[] = "buffer: $num";
'buffer' => function ($num) use (&$calls) {
$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);
@ -489,19 +531,13 @@ class QueryExecutionTest extends ServerTestCase
$expected = [
[
'data' => [
'dfd' => 'loaded: 1'
]
'data' => ['dfd' => 'loaded: 1'],
],
[
'data' => [
'dfd' => 'loaded: 2'
]
'data' => ['dfd' => 'loaded: 2'],
],
[
'data' => [
'dfd' => 'loaded: 3'
]
'data' => ['dfd' => 'loaded: 3'],
],
];
@ -512,7 +548,7 @@ class QueryExecutionTest extends ServerTestCase
public function testValidatesParamsBeforeExecution() : void
{
$op = OperationParams::create(['queryBad' => '{f1}']);
$op = OperationParams::create(['queryBad' => '{f1}']);
$helper = new Helper();
$result = $helper->executeOperation($this->config, $op);
$this->assertInstanceOf(ExecutionResult::class, $result);
@ -536,10 +572,10 @@ class QueryExecutionTest extends ServerTestCase
$called = false;
$params = $doc = $operationType = null;
$this->config->setContext(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
$called = true;
$params = $p;
$doc = $d;
$this->config->setContext(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
$called = true;
$params = $p;
$doc = $d;
$operationType = $o;
});
@ -556,10 +592,10 @@ class QueryExecutionTest extends ServerTestCase
$called = false;
$params = $doc = $operationType = null;
$this->config->setRootValue(function($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
$called = true;
$params = $p;
$doc = $d;
$this->config->setRootValue(function ($p, $d, $o) use (&$called, &$params, &$doc, &$operationType) {
$called = true;
$params = $p;
$doc = $d;
$operationType = $o;
});
@ -574,20 +610,21 @@ class QueryExecutionTest extends ServerTestCase
public function testAppliesErrorFormatter() : void
{
$called = false;
$error = null;
$this->config->setErrorFormatter(function($e) use (&$called, &$error) {
$error = null;
$this->config->setErrorFormatter(function ($e) use (&$called, &$error) {
$called = true;
$error = $e;
$error = $e;
return ['test' => 'formatted'];
});
$result = $this->executeQuery('{fieldWithException}');
$this->assertFalse($called);
$formatted = $result->toArray();
$expected = [
$expected = [
'errors' => [
['test' => 'formatted']
]
['test' => 'formatted'],
],
];
$this->assertTrue($called);
$this->assertArraySubset($expected, $formatted);
@ -595,28 +632,29 @@ class QueryExecutionTest extends ServerTestCase
// Assert debugging still works even with custom formatter
$formatted = $result->toArray(Debug::INCLUDE_TRACE);
$expected = [
$expected = [
'errors' => [
[
'test' => 'formatted',
'trace' => []
]
]
'test' => 'formatted',
'trace' => [],
],
],
];
$this->assertArraySubset($expected, $formatted);
}
public function testAppliesErrorsHandler() : void
{
$called = false;
$errors = null;
$called = false;
$errors = null;
$formatter = null;
$this->config->setErrorsHandler(function($e, $f) use (&$called, &$errors, &$formatter) {
$called = true;
$errors = $e;
$this->config->setErrorsHandler(function ($e, $f) use (&$called, &$errors, &$formatter) {
$called = true;
$errors = $e;
$formatter = $f;
return [
['test' => 'handled']
['test' => 'handled'],
];
});
@ -624,10 +662,10 @@ class QueryExecutionTest extends ServerTestCase
$this->assertFalse($called);
$formatted = $result->toArray();
$expected = [
$expected = [
'errors' => [
['test' => 'handled']
]
['test' => 'handled'],
],
];
$this->assertTrue($called);
$this->assertArraySubset($expected, $formatted);
@ -636,46 +674,4 @@ class QueryExecutionTest extends ServerTestCase
$this->assertInternalType('callable', $formatter);
$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
declare(strict_types=1);
namespace GraphQL\Tests\Server;
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation;
use GraphQL\Server\Helper;
use GraphQL\Server\OperationParams;
@ -9,15 +11,17 @@ use GraphQL\Server\RequestError;
use GraphQL\Tests\Server\Psr7\PsrRequestStub;
use GraphQL\Tests\Server\Psr7\PsrStreamStub;
use PHPUnit\Framework\TestCase;
use function json_decode;
use function json_encode;
class RequestParsingTest extends TestCase
{
public function testParsesGraphqlRequest() : void
{
$query = '{my query}';
$query = '{my query}';
$parsed = [
'raw' => $this->parseRawRequest('application/graphql', $query),
'psr' => $this->parsePsrRequest('application/graphql', $query)
'psr' => $this->parsePsrRequest('application/graphql', $query),
];
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
{
$query = '{my query}';
$query = '{my query}';
$variables = ['test' => 1, 'test2' => 2];
$operation = 'op';
$post = [
'query' => $query,
'variables' => $variables,
'operationName' => $operation
$post = [
'query' => $query,
'variables' => $variables,
'operationName' => $operation,
];
$parsed = [
'raw' => $this->parseRawFormUrlencodedRequest($post),
'psr' => $this->parsePsrFormUrlEncodedRequest($post)
'psr' => $this->parsePsrFormUrlEncodedRequest($post),
];
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
{
$query = '{my query}';
$query = '{my query}';
$variables = ['test' => 1, 'test2' => 2];
$operation = 'op';
$get = [
'query' => $query,
'variables' => $variables,
'operationName' => $operation
$get = [
'query' => $query,
'variables' => $variables,
'operationName' => $operation,
];
$parsed = [
'raw' => $this->parseRawGetRequest($get),
'psr' => $this->parsePsrGetRequest($get)
'psr' => $this->parsePsrGetRequest($get),
];
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
{
$query = '{my query}';
$query = '{my query}';
$variables = ['test' => 1, 'test2' => 2];
$operation = 'op';
$post = [
'query' => $query,
'variables' => $variables,
'operationName' => $operation
$post = [
'query' => $query,
'variables' => $variables,
'operationName' => $operation,
];
$parsed = [
'raw' => $this->parseRawMultipartFormdataRequest($post),
'psr' => $this->parsePsrMultipartFormdataRequest($post)
'psr' => $this->parsePsrMultipartFormdataRequest($post),
];
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
{
$query = '{my query}';
$query = '{my query}';
$variables = ['test' => 1, 'test2' => 2];
$operation = 'op';
$body = [
'query' => $query,
'variables' => $variables,
'operationName' => $operation
$body = [
'query' => $query,
'variables' => $variables,
'operationName' => $operation,
];
$parsed = [
'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) {
$this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method);
@ -115,18 +287,18 @@ class RequestParsingTest extends TestCase
public function testParsesVariablesAsJSON() : void
{
$query = '{my query}';
$query = '{my query}';
$variables = ['test' => 1, 'test2' => 2];
$operation = 'op';
$body = [
'query' => $query,
'variables' => json_encode($variables),
'operationName' => $operation
$body = [
'query' => $query,
'variables' => json_encode($variables),
'operationName' => $operation,
];
$parsed = [
'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) {
$this->assertValidOperationParams($parsedBody, $query, null, $variables, $operation, $method);
@ -136,14 +308,14 @@ class RequestParsingTest extends TestCase
public function testIgnoresInvalidVariablesJson() : void
{
$query = '{my query}';
$query = '{my query}';
$variables = '"some invalid json';
$operation = 'op';
$body = [
'query' => $query,
'variables' => $variables,
'operationName' => $operation
$body = [
'query' => $query,
'variables' => $variables,
'operationName' => $operation,
];
$parsed = [
'raw' => $this->parseRawRequest('application/json', json_encode($body)),
@ -157,27 +329,41 @@ class RequestParsingTest extends TestCase
public function testParsesBatchJSONRequest() : void
{
$body = [
$body = [
[
'query' => '{my query}',
'variables' => ['test' => 1, 'test2' => 2],
'operationName' => 'op'
'query' => '{my query}',
'variables' => ['test' => 1, 'test2' => 2],
'operationName' => 'op',
],
[
'queryId' => 'my-query-id',
'variables' => ['test' => 1, 'test2' => 2],
'operationName' => 'op2'
'queryId' => 'my-query-id',
'variables' => ['test' => 1, 'test2' => 2],
'operationName' => 'op2',
],
];
$parsed = [
'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) {
$this->assertInternalType('array', $parsedBody, $method);
$this->assertCount(2, $parsedBody, $method);
$this->assertValidOperationParams($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);
$this->assertValidOperationParams(
$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->expectExceptionMessage('Could not parse JSON: Syntax error');
$this->parseRawRequest('application/json', $body);
}
$this->parseRawRequest('application/json', $body);
}
public function testFailsParsingInvalidRawJsonRequestPsr() : void
{
@ -196,7 +382,7 @@ class RequestParsingTest extends TestCase
$this->expectException(InvariantViolation::class);
$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
@ -222,8 +408,8 @@ class RequestParsingTest extends TestCase
$this->expectException(RequestError::class);
$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
{
@ -231,13 +417,13 @@ class RequestParsingTest extends TestCase
$this->expectException(RequestError::class);
$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
{
$contentType = 'not-supported-content-type';
$body = 'test';
$body = 'test';
$this->expectException(RequestError::class);
$this->expectExceptionMessage('Unexpected content type: "not-supported-content-type"');
@ -247,194 +433,38 @@ class RequestParsingTest extends TestCase
public function testFailsParsingInvalidContentTypePsr() : void
{
$contentType = 'not-supported-content-type';
$body = 'test';
$body = 'test';
$this->expectException(RequestError::class);
$this->expectExceptionMessage('Unexpected content type: "not-supported-content-type"');
$this->parseRawRequest($contentType, $body);
}
$this->parseRawRequest($contentType, $body);
}
public function testFailsWithMissingContentTypeRaw() : void
{
$this->expectException(RequestError::class);
$this->expectExceptionMessage('Missing "Content-Type" header');
$this->parseRawRequest(null, 'test');
}
$this->parseRawRequest(null, 'test');
}
public function testFailsWithMissingContentTypePsr() : void
{
$this->expectException(RequestError::class);
$this->expectExceptionMessage('Missing "Content-Type" header');
$this->parsePsrRequest(null, 'test');
$this->parsePsrRequest(null, 'test');
}
public function testFailsOnMethodsOtherThanPostOrGetRaw() : void
{
$this->expectException(RequestError::class);
$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
{
$this->expectException(RequestError::class);
$this->expectExceptionMessage('HTTP Method "PUT" is not supported');
$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);
$this->parsePsrRequest('application/json', json_encode([]), 'PUT');
}
}

View File

@ -1,4 +1,7 @@
<?php
declare(strict_types=1);
namespace GraphQL\Tests\Server;
use GraphQL\Server\Helper;
@ -9,28 +12,35 @@ class RequestValidationTest extends TestCase
{
public function testSimpleRequestShouldValidate() : void
{
$query = '{my q}';
$query = '{my q}';
$variables = ['a' => 'b', 'c' => 'd'];
$operation = 'op';
$parsedBody = OperationParams::create([
'query' => $query,
'variables' => $variables,
'query' => $query,
'variables' => $variables,
'operationName' => $operation,
]);
$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
{
$queryId = 'some-query-id';
$queryId = 'some-query-id';
$variables = ['a' => 'b', 'c' => 'd'];
$operation = 'op';
$parsedBody = OperationParams::create([
'queryId' => $queryId,
'variables' => $variables,
'queryId' => $queryId,
'variables' => $variables,
'operationName' => $operation,
]);
@ -40,7 +50,7 @@ class RequestValidationTest extends TestCase
public function testRequiresQueryOrQueryId() : void
{
$parsedBody = OperationParams::create([
'variables' => ['foo' => 'bar'],
'variables' => ['foo' => 'bar'],
'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
{
$parsedBody = OperationParams::create([
'query' => '{my query}',
'query' => '{my query}',
'queryId' => 'my-query-id',
]);
@ -66,7 +87,7 @@ class RequestValidationTest extends TestCase
public function testFailsWhenQueryParameterIsNotString() : void
{
$parsedBody = OperationParams::create([
'query' => ['t' => '{my query}']
'query' => ['t' => '{my query}'],
]);
$this->assertInputError(
@ -78,7 +99,7 @@ class RequestValidationTest extends TestCase
public function testFailsWhenQueryIdParameterIsNotString() : void
{
$parsedBody = OperationParams::create([
'queryId' => ['t' => '{my query}']
'queryId' => ['t' => '{my query}'],
]);
$this->assertInputError(
@ -90,8 +111,8 @@ class RequestValidationTest extends TestCase
public function testFailsWhenOperationParameterIsNotString() : void
{
$parsedBody = OperationParams::create([
'query' => '{my query}',
'operationName' => []
'query' => '{my query}',
'operationName' => [],
]);
$this->assertInputError(
@ -105,17 +126,17 @@ class RequestValidationTest extends TestCase
*/
public function testIgnoresNullAndEmptyStringVariables() : void
{
$query = '{my q}';
$query = '{my q}';
$parsedBody = OperationParams::create([
'query' => $query,
'variables' => null
'query' => $query,
'variables' => null,
]);
$this->assertValid($parsedBody);
$variables = "";
$variables = '';
$parsedBody = OperationParams::create([
'query' => $query,
'variables' => $variables
'query' => $query,
'variables' => $variables,
]);
$this->assertValid($parsedBody);
}
@ -123,8 +144,8 @@ class RequestValidationTest extends TestCase
public function testFailsWhenVariablesParameterIsNotObject() : void
{
$parsedBody = OperationParams::create([
'query' => '{my query}',
'variables' => 0
'query' => '{my query}',
'variables' => 0,
]);
$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'
);
}
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
declare(strict_types=1);
namespace GraphQL\Tests\Server;
use GraphQL\Error\InvariantViolation;
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
use GraphQL\Type\Schema;
use GraphQL\Server\ServerConfig;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
use PHPUnit\Framework\TestCase;
class ServerConfigTest extends TestCase
@ -70,7 +73,8 @@ class ServerConfigTest extends TestCase
{
$config = ServerConfig::create();
$formatter = function() {};
$formatter = function () {
};
$config->setErrorFormatter($formatter);
$this->assertSame($formatter, $config->getErrorFormatter());
@ -83,7 +87,8 @@ class ServerConfigTest extends TestCase
{
$config = ServerConfig::create();
$handler = function() {};
$handler = function () {
};
$config->setErrorsHandler($handler);
$this->assertSame($handler, $config->getErrorsHandler());
@ -113,11 +118,17 @@ class ServerConfigTest extends TestCase
$config->setValidationRules($rules);
$this->assertSame($rules, $config->getValidationRules());
$rules = [function() {}];
$rules = [function () {
},
];
$config->setValidationRules($rules);
$this->assertSame($rules, $config->getValidationRules());
$rules = function() {return [function() {}];};
$rules = function () {
return [function () {
},
];
};
$config->setValidationRules($rules);
$this->assertSame($rules, $config->getValidationRules());
}
@ -126,7 +137,8 @@ class ServerConfigTest extends TestCase
{
$config = ServerConfig::create();
$resolver = function() {};
$resolver = function () {
};
$config->setFieldResolver($resolver);
$this->assertSame($resolver, $config->getFieldResolver());
@ -139,7 +151,8 @@ class ServerConfigTest extends TestCase
{
$config = ServerConfig::create();
$loader = function() {};
$loader = function () {
};
$config->setPersistentQueryLoader($loader);
$this->assertSame($loader, $config->getPersistentQueryLoader());
@ -162,18 +175,23 @@ class ServerConfigTest extends TestCase
public function testAcceptsArray() : void
{
$arr = [
'schema' => new \GraphQL\Type\Schema([
'query' => new ObjectType(['name' => 't', 'fields' => ['a' => Type::string()]])
'schema' => new Schema([
'query' => new ObjectType(['name' => 't', 'fields' => ['a' => Type::string()]]),
]),
'context' => new \stdClass(),
'rootValue' => new \stdClass(),
'errorFormatter' => function() {},
'promiseAdapter' => new SyncPromiseAdapter(),
'validationRules' => [function() {}],
'fieldResolver' => function() {},
'persistentQueryLoader' => function() {},
'debug' => true,
'queryBatching' => true,
'context' => new \stdClass(),
'rootValue' => new \stdClass(),
'errorFormatter' => function () {
},
'promiseAdapter' => new SyncPromiseAdapter(),
'validationRules' => [function () {
},
],
'fieldResolver' => function () {
},
'persistentQueryLoader' => function () {
},
'debug' => true,
'queryBatching' => true,
];
$config = ServerConfig::create($arr);
@ -192,9 +210,7 @@ class ServerConfigTest extends TestCase
public function testThrowsOnInvalidArrayKey() : void
{
$arr = [
'missingKey' => 'value'
];
$arr = ['missingKey' => 'value'];
$this->expectException(InvariantViolation::class);
$this->expectExceptionMessage('Unknown server config option "missingKey"');
@ -204,7 +220,7 @@ class ServerConfigTest extends TestCase
public function testInvalidValidationRules() : void
{
$rules = new \stdClass();
$rules = new \stdClass();
$config = ServerConfig::create();
$this->expectException(InvariantViolation::class);

View File

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

View File

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