mirror of
https://github.com/retailcrm/graphql-php.git
synced 2025-02-06 07:49:24 +03:00
Tests for new GraphQL\Server facade
This commit is contained in:
parent
8e75cc3d60
commit
e2875953e1
134
src/Server.php
134
src/Server.php
@ -2,11 +2,11 @@
|
|||||||
namespace GraphQL;
|
namespace GraphQL;
|
||||||
|
|
||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Executor\ExecutionResult;
|
use GraphQL\Executor\ExecutionResult;
|
||||||
use GraphQL\Executor\Promise\PromiseAdapter;
|
use GraphQL\Executor\Promise\PromiseAdapter;
|
||||||
use GraphQL\Language\AST\DocumentNode;
|
use GraphQL\Language\AST\DocumentNode;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
use GraphQL\Type\Definition\Config;
|
|
||||||
use GraphQL\Type\Definition\Directive;
|
use GraphQL\Type\Definition\Directive;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
@ -17,7 +17,6 @@ class Server
|
|||||||
{
|
{
|
||||||
const DEBUG_PHP_ERRORS = 1;
|
const DEBUG_PHP_ERRORS = 1;
|
||||||
const DEBUG_EXCEPTIONS = 2;
|
const DEBUG_EXCEPTIONS = 2;
|
||||||
const DEBUG_SCHEMA_CONFIGS = 4;
|
|
||||||
const DEBUG_ALL = 7;
|
const DEBUG_ALL = 7;
|
||||||
|
|
||||||
private $queryType;
|
private $queryType;
|
||||||
@ -88,6 +87,7 @@ class Server
|
|||||||
*/
|
*/
|
||||||
public function setQueryType(ObjectType $queryType)
|
public function setQueryType(ObjectType $queryType)
|
||||||
{
|
{
|
||||||
|
$this->assertSchemaNotSet('Query Type', __METHOD__);
|
||||||
$this->queryType = $queryType;
|
$this->queryType = $queryType;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -106,6 +106,7 @@ class Server
|
|||||||
*/
|
*/
|
||||||
public function setMutationType(ObjectType $mutationType)
|
public function setMutationType(ObjectType $mutationType)
|
||||||
{
|
{
|
||||||
|
$this->assertSchemaNotSet('Mutation Type', __METHOD__);
|
||||||
$this->mutationType = $mutationType;
|
$this->mutationType = $mutationType;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -124,6 +125,7 @@ class Server
|
|||||||
*/
|
*/
|
||||||
public function setSubscriptionType($subscriptionType)
|
public function setSubscriptionType($subscriptionType)
|
||||||
{
|
{
|
||||||
|
$this->assertSchemaNotSet('Subscription Type', __METHOD__);
|
||||||
$this->subscriptionType = $subscriptionType;
|
$this->subscriptionType = $subscriptionType;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -134,10 +136,16 @@ class Server
|
|||||||
*/
|
*/
|
||||||
public function addTypes(array $types)
|
public function addTypes(array $types)
|
||||||
{
|
{
|
||||||
$this->types = array_merge($this->types, $types);
|
if (!empty($types)) {
|
||||||
|
$this->assertSchemaNotSet('Types', __METHOD__);
|
||||||
|
$this->types = array_merge($this->types, $types);
|
||||||
|
}
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getTypes()
|
public function getTypes()
|
||||||
{
|
{
|
||||||
return $this->types;
|
return $this->types;
|
||||||
@ -161,6 +169,7 @@ class Server
|
|||||||
*/
|
*/
|
||||||
public function setDirectives(array $directives)
|
public function setDirectives(array $directives)
|
||||||
{
|
{
|
||||||
|
$this->assertSchemaNotSet('Directives', __METHOD__);
|
||||||
$this->directives = $directives;
|
$this->directives = $directives;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -219,6 +228,58 @@ class Server
|
|||||||
return $this->rootValue;
|
return $this->rootValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set schema instance manually. Mutually exclusive with `setQueryType`, `setMutationType`, `setSubscriptionType`, `setDirectives`, `addTypes`
|
||||||
|
*
|
||||||
|
* @param Schema $schema
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setSchema(Schema $schema)
|
||||||
|
{
|
||||||
|
if ($this->queryType) {
|
||||||
|
$err = 'Query Type is already set';
|
||||||
|
$errMethod = __CLASS__ . '::setQueryType';
|
||||||
|
} else if ($this->mutationType) {
|
||||||
|
$err = 'Mutation Type is already set';
|
||||||
|
$errMethod = __CLASS__ . '::setMutationType';
|
||||||
|
} else if ($this->subscriptionType) {
|
||||||
|
$err = 'Subscription Type is already set';
|
||||||
|
$errMethod = __CLASS__ . '::setSubscriptionType';
|
||||||
|
} else if ($this->directives) {
|
||||||
|
$err = 'Directives are already set';
|
||||||
|
$errMethod = __CLASS__ . '::setDirectives';
|
||||||
|
} else if ($this->types) {
|
||||||
|
$err = 'Additional types are already set';
|
||||||
|
$errMethod = __CLASS__ . '::addTypes';
|
||||||
|
} else if ($this->typeResolutionStrategy) {
|
||||||
|
$err = 'Type Resolution Strategy is already set';
|
||||||
|
$errMethod = __CLASS__ . '::setTypeResolutionStrategy';
|
||||||
|
} else if ($this->schema && $this->schema !== $schema) {
|
||||||
|
$err = 'Different schema is already set';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($err)) {
|
||||||
|
if (isset($errMethod)) {
|
||||||
|
$err .= " ($errMethod is mutually exclusive with " . __METHOD__ . ")";
|
||||||
|
}
|
||||||
|
throw new InvariantViolation("Cannot set Schema on Server: $err");
|
||||||
|
}
|
||||||
|
$this->schema = $schema;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $entry
|
||||||
|
* @param $mutuallyExclusiveMethod
|
||||||
|
*/
|
||||||
|
private function assertSchemaNotSet($entry, $mutuallyExclusiveMethod)
|
||||||
|
{
|
||||||
|
if ($this->schema) {
|
||||||
|
$schemaMethod = __CLASS__ . '::setSchema';
|
||||||
|
throw new InvariantViolation("Cannot set $entry on Server: Schema is already set ($mutuallyExclusiveMethod is mutually exclusive with $schemaMethod)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Schema
|
* @return Schema
|
||||||
*/
|
*/
|
||||||
@ -246,6 +307,8 @@ class Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Expects function(\ErrorException $e) : array
|
||||||
|
*
|
||||||
* @param callable $phpErrorFormatter
|
* @param callable $phpErrorFormatter
|
||||||
*/
|
*/
|
||||||
public function setPhpErrorFormatter(callable $phpErrorFormatter)
|
public function setPhpErrorFormatter(callable $phpErrorFormatter)
|
||||||
@ -262,6 +325,8 @@ class Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Expects function(Exception $e) : array
|
||||||
|
*
|
||||||
* @param callable $exceptionFormatter
|
* @param callable $exceptionFormatter
|
||||||
*/
|
*/
|
||||||
public function setExceptionFormatter(callable $exceptionFormatter)
|
public function setExceptionFormatter(callable $exceptionFormatter)
|
||||||
@ -302,8 +367,11 @@ class Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Parses GraphQL query string and returns Abstract Syntax Tree for this query
|
||||||
|
*
|
||||||
* @param string $query
|
* @param string $query
|
||||||
* @return Language\AST\DocumentNode
|
* @return Language\AST\DocumentNode
|
||||||
|
* @throws \GraphQL\Error\SyntaxError
|
||||||
*/
|
*/
|
||||||
public function parse($query)
|
public function parse($query)
|
||||||
{
|
{
|
||||||
@ -323,10 +391,12 @@ class Server
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $validationRules
|
* @param array $validationRules
|
||||||
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setValidationRules(array $validationRules)
|
public function setValidationRules(array $validationRules)
|
||||||
{
|
{
|
||||||
$this->validationRules = $validationRules;
|
$this->validationRules = $validationRules;
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -343,12 +413,13 @@ class Server
|
|||||||
*/
|
*/
|
||||||
public function setTypeResolutionStrategy(Resolution $typeResolutionStrategy)
|
public function setTypeResolutionStrategy(Resolution $typeResolutionStrategy)
|
||||||
{
|
{
|
||||||
|
$this->assertSchemaNotSet('Type Resolution Strategy', __METHOD__);
|
||||||
$this->typeResolutionStrategy = $typeResolutionStrategy;
|
$this->typeResolutionStrategy = $typeResolutionStrategy;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return PromiseAdapter
|
* @return PromiseAdapter|null
|
||||||
*/
|
*/
|
||||||
public function getPromiseAdapter()
|
public function getPromiseAdapter()
|
||||||
{
|
{
|
||||||
@ -363,22 +434,33 @@ class Server
|
|||||||
*/
|
*/
|
||||||
public function setPromiseAdapter(PromiseAdapter $promiseAdapter)
|
public function setPromiseAdapter(PromiseAdapter $promiseAdapter)
|
||||||
{
|
{
|
||||||
|
if ($this->promiseAdapter && $promiseAdapter !== $this->promiseAdapter) {
|
||||||
|
throw new InvariantViolation("Cannot set promise adapter: Different adapter is already set");
|
||||||
|
}
|
||||||
$this->promiseAdapter = $promiseAdapter;
|
$this->promiseAdapter = $promiseAdapter;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns array with validation errors
|
* Returns array with validation errors (empty when there are no validation errors)
|
||||||
*
|
*
|
||||||
* @param DocumentNode $query
|
* @param DocumentNode $query
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function validate(DocumentNode $query)
|
public function validate(DocumentNode $query)
|
||||||
{
|
{
|
||||||
return DocumentValidator::validate($this->getSchema(), $query, $this->validationRules);
|
try {
|
||||||
|
$schema = $this->getSchema();
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
throw new InvariantViolation("Cannot validate, schema contains errors: {$e->getMessage()}", null, $e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DocumentValidator::validate($schema, $query, $this->validationRules);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Executes GraphQL query against this server and returns execution result
|
||||||
|
*
|
||||||
* @param string|DocumentNode $query
|
* @param string|DocumentNode $query
|
||||||
* @param array|null $variables
|
* @param array|null $variables
|
||||||
* @param string|null $operationName
|
* @param string|null $operationName
|
||||||
@ -389,17 +471,10 @@ class Server
|
|||||||
$this->phpErrors = [];
|
$this->phpErrors = [];
|
||||||
if ($this->debug & static::DEBUG_PHP_ERRORS) {
|
if ($this->debug & static::DEBUG_PHP_ERRORS) {
|
||||||
// Catch custom errors (to report them in query results)
|
// Catch custom errors (to report them in query results)
|
||||||
$lastDisplayErrors = ini_get('display_errors');
|
|
||||||
ini_set('display_errors', 0);
|
|
||||||
|
|
||||||
set_error_handler(function($severity, $message, $file, $line) {
|
set_error_handler(function($severity, $message, $file, $line) {
|
||||||
$this->phpErrors[] = new \ErrorException($message, 0, $severity, $file, $line);
|
$this->phpErrors[] = new \ErrorException($message, 0, $severity, $file, $line);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if ($this->debug & static::DEBUG_SCHEMA_CONFIGS) {
|
|
||||||
$isConfigValidationEnabled = Config::isValidationEnabled();
|
|
||||||
Config::enableValidation();
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = GraphQL::executeAndReturnResult(
|
$result = GraphQL::executeAndReturnResult(
|
||||||
$this->getSchema(),
|
$this->getSchema(),
|
||||||
@ -420,38 +495,40 @@ class Server
|
|||||||
$result->extensions['phpErrors'] = array_map($this->phpErrorFormatter, $this->phpErrors);
|
$result->extensions['phpErrors'] = array_map($this->phpErrorFormatter, $this->phpErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($lastDisplayErrors)) {
|
if ($this->debug & static::DEBUG_PHP_ERRORS) {
|
||||||
ini_set('display_errors', $lastDisplayErrors);
|
|
||||||
restore_error_handler();
|
restore_error_handler();
|
||||||
}
|
}
|
||||||
if (isset($isConfigValidationEnabled) && !$isConfigValidationEnabled) {
|
|
||||||
Config::disableValidation();
|
|
||||||
}
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GraphQL HTTP endpoint compatible with express-graphql
|
||||||
|
*/
|
||||||
public function handleRequest()
|
public function handleRequest()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$httpStatus = 200;
|
$httpStatus = 200;
|
||||||
if (isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) {
|
if (isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) {
|
||||||
$raw = file_get_contents('php://input') ?: '';
|
$raw = $this->readInput();
|
||||||
$data = json_decode($raw, true);
|
$data = json_decode($raw, true);
|
||||||
} else {
|
} else {
|
||||||
$data = $_REQUEST;
|
$data = $_REQUEST;
|
||||||
}
|
}
|
||||||
$data += ['query' => null, 'variables' => null];
|
$data += ['query' => null, 'variables' => null];
|
||||||
$result = $this->executeQuery($data['query'], (array) $data['variables'])->toArray();
|
$result = $this->executeQuery($data['query'], (array) $data['variables'])->toArray();
|
||||||
} catch (\Exception $exception) {
|
} catch (\Exception $e) {
|
||||||
// This is only possible for schema creation errors and some very unpredictable errors,
|
// This is only possible for schema creation errors and some very unpredictable errors,
|
||||||
// (all errors which occur during query execution are caught and included in final response)
|
// (all errors which occur during query execution are caught and included in final response)
|
||||||
$httpStatus = $this->unexpectedErrorStatus;
|
$httpStatus = $this->unexpectedErrorStatus;
|
||||||
$error = new Error($this->unexpectedErrorMessage, null, null, null, null, $exception);
|
$error = new Error($this->unexpectedErrorMessage, null, null, null, null, $e);
|
||||||
|
$result = ['errors' => [$this->formatError($error)]];
|
||||||
|
} catch (\Error $e) {
|
||||||
|
$httpStatus = $this->unexpectedErrorStatus;
|
||||||
|
$error = new Error($this->unexpectedErrorMessage, null, null, null, null, $e);
|
||||||
$result = ['errors' => [$this->formatError($error)]];
|
$result = ['errors' => [$this->formatError($error)]];
|
||||||
}
|
}
|
||||||
|
|
||||||
header('Content-Type: application/json', true, $httpStatus);
|
$this->produceOutput($result, $httpStatus);
|
||||||
echo json_encode($result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function formatException(\Exception $e)
|
private function formatException(\Exception $e)
|
||||||
@ -473,4 +550,15 @@ class Server
|
|||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function readInput()
|
||||||
|
{
|
||||||
|
return file_get_contents('php://input') ?: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function produceOutput(array $result, $httpStatus)
|
||||||
|
{
|
||||||
|
header('Content-Type: application/json', true, $httpStatus);
|
||||||
|
echo json_encode($result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests;
|
namespace GraphQL\Tests;
|
||||||
|
|
||||||
|
use GraphQL\Error\Error;
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
|
use GraphQL\Executor\ExecutionResult;
|
||||||
|
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
|
||||||
|
use GraphQL\Schema;
|
||||||
use GraphQL\Server;
|
use GraphQL\Server;
|
||||||
use GraphQL\Type\Definition\Directive;
|
use GraphQL\Type\Definition\Directive;
|
||||||
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
|
use GraphQL\Type\Definition\ResolveInfo;
|
||||||
|
use GraphQL\Type\Definition\Type;
|
||||||
|
use GraphQL\Type\EagerResolution;
|
||||||
use GraphQL\Validator\DocumentValidator;
|
use GraphQL\Validator\DocumentValidator;
|
||||||
|
|
||||||
class ServerTest extends \PHPUnit_Framework_TestCase
|
class ServerTest extends \PHPUnit_Framework_TestCase
|
||||||
@ -14,14 +22,17 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals(null, $server->getQueryType());
|
$this->assertEquals(null, $server->getQueryType());
|
||||||
$this->assertEquals(null, $server->getMutationType());
|
$this->assertEquals(null, $server->getMutationType());
|
||||||
$this->assertEquals(null, $server->getSubscriptionType());
|
$this->assertEquals(null, $server->getSubscriptionType());
|
||||||
|
$this->assertEquals(Directive::getInternalDirectives(), $server->getDirectives());
|
||||||
|
$this->assertEquals([], $server->getTypes());
|
||||||
|
$this->assertEquals(null, $server->getTypeResolutionStrategy());
|
||||||
|
|
||||||
$this->assertEquals(null, $server->getContext());
|
$this->assertEquals(null, $server->getContext());
|
||||||
$this->assertEquals(null, $server->getRootValue());
|
$this->assertEquals(null, $server->getRootValue());
|
||||||
$this->assertEquals(0, $server->getDebug());
|
$this->assertEquals(0, $server->getDebug());
|
||||||
$this->assertEquals(Directive::getInternalDirectives(), $server->getDirectives());
|
|
||||||
$this->assertEquals(['GraphQL\Error\FormattedError', 'createFromException'], $server->getExceptionFormatter());
|
$this->assertEquals(['GraphQL\Error\FormattedError', 'createFromException'], $server->getExceptionFormatter());
|
||||||
$this->assertEquals(['GraphQL\Error\FormattedError', 'createFromPHPError'], $server->getPhpErrorFormatter());
|
$this->assertEquals(['GraphQL\Error\FormattedError', 'createFromPHPError'], $server->getPhpErrorFormatter());
|
||||||
$this->assertEquals(null, $server->getPromiseAdapter());
|
$this->assertEquals(null, $server->getPromiseAdapter());
|
||||||
$this->assertEquals(null, $server->getTypeResolutionStrategy());
|
|
||||||
$this->assertEquals('Unexpected Error', $server->getUnexpectedErrorMessage());
|
$this->assertEquals('Unexpected Error', $server->getUnexpectedErrorMessage());
|
||||||
$this->assertEquals(500, $server->getUnexpectedErrorStatus());
|
$this->assertEquals(500, $server->getUnexpectedErrorStatus());
|
||||||
$this->assertEquals(DocumentValidator::allRules(), $server->getValidationRules());
|
$this->assertEquals(DocumentValidator::allRules(), $server->getValidationRules());
|
||||||
@ -33,4 +44,533 @@ class ServerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals('Schema query must be Object Type but got: NULL', $e->getMessage());
|
$this->assertEquals('Schema query must be Object Type but got: NULL', $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSchemaDefinition()
|
||||||
|
{
|
||||||
|
$mutationType = $queryType = $subscriptionType = new ObjectType(['name' => 'A', 'fields' => []]);
|
||||||
|
|
||||||
|
$schema = new Schema([
|
||||||
|
'query' => $queryType
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setQueryType($queryType)
|
||||||
|
->setSchema($schema);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Schema on Server: Query Type is already set '.
|
||||||
|
'(GraphQL\Server::setQueryType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setMutationType($mutationType)
|
||||||
|
->setSchema($schema);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Schema on Server: Mutation Type is already set '.
|
||||||
|
'(GraphQL\Server::setMutationType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setSubscriptionType($subscriptionType)
|
||||||
|
->setSchema($schema);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Schema on Server: Subscription Type is already set '.
|
||||||
|
'(GraphQL\Server::setSubscriptionType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setDirectives(Directive::getInternalDirectives())
|
||||||
|
->setSchema($schema);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Schema on Server: Directives are already set '.
|
||||||
|
'(GraphQL\Server::setDirectives is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->addTypes([$queryType, $mutationType])
|
||||||
|
->setSchema($schema);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Schema on Server: Additional types are already set '.
|
||||||
|
'(GraphQL\Server::addTypes is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setTypeResolutionStrategy(new EagerResolution([$queryType, $mutationType]))
|
||||||
|
->setSchema($schema);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Schema on Server: Type Resolution Strategy is already set '.
|
||||||
|
'(GraphQL\Server::setTypeResolutionStrategy is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setSchema($schema)
|
||||||
|
->setQueryType($queryType);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Query Type on Server: Schema is already set '.
|
||||||
|
'(GraphQL\Server::setQueryType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setSchema($schema)
|
||||||
|
->setMutationType($mutationType);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Mutation Type on Server: Schema is already set '.
|
||||||
|
'(GraphQL\Server::setMutationType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setSchema($schema)
|
||||||
|
->setSubscriptionType($subscriptionType);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Subscription Type on Server: Schema is already set '.
|
||||||
|
'(GraphQL\Server::setSubscriptionType is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setSchema($schema)
|
||||||
|
->setDirectives([]);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Directives on Server: Schema is already set '.
|
||||||
|
'(GraphQL\Server::setDirectives is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setSchema($schema)
|
||||||
|
->addTypes([$queryType, $mutationType]);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Types on Server: Schema is already set '.
|
||||||
|
'(GraphQL\Server::addTypes is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// But empty types should work (as they don't change anything):
|
||||||
|
Server::create()
|
||||||
|
->setSchema($schema)
|
||||||
|
->addTypes([]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setSchema($schema)
|
||||||
|
->setTypeResolutionStrategy(new EagerResolution([$queryType, $mutationType]));
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Type Resolution Strategy on Server: Schema is already set '.
|
||||||
|
'(GraphQL\Server::setTypeResolutionStrategy is mutually exclusive with GraphQL\Server::setSchema)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Server::create()
|
||||||
|
->setSchema($schema)
|
||||||
|
->setSchema(new Schema(['query' => $queryType]));
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set Schema on Server: Different schema is already set',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This should not throw:
|
||||||
|
$server = Server::create()
|
||||||
|
->setSchema($schema);
|
||||||
|
|
||||||
|
$this->assertSame($schema, $server->getSchema());
|
||||||
|
|
||||||
|
$server = Server::create()
|
||||||
|
->setQueryType($queryType);
|
||||||
|
$this->assertSame($queryType, $server->getQueryType());
|
||||||
|
$this->assertSame($queryType, $server->getSchema()->getQueryType());
|
||||||
|
|
||||||
|
$server = Server::create()
|
||||||
|
->setQueryType($queryType)
|
||||||
|
->setMutationType($mutationType);
|
||||||
|
|
||||||
|
$this->assertSame($mutationType, $server->getMutationType());
|
||||||
|
$this->assertSame($mutationType, $server->getSchema()->getMutationType());
|
||||||
|
|
||||||
|
$server = Server::create()
|
||||||
|
->setQueryType($queryType)
|
||||||
|
->setSubscriptionType($subscriptionType);
|
||||||
|
|
||||||
|
$this->assertSame($subscriptionType, $server->getSubscriptionType());
|
||||||
|
$this->assertSame($subscriptionType, $server->getSchema()->getSubscriptionType());
|
||||||
|
|
||||||
|
$server = Server::create()
|
||||||
|
->setQueryType($queryType)
|
||||||
|
->addTypes($types = [$queryType, $subscriptionType]);
|
||||||
|
|
||||||
|
$this->assertSame($types, $server->getTypes());
|
||||||
|
$server->addTypes([$mutationType]);
|
||||||
|
$this->assertSame(array_merge($types, [$mutationType]), $server->getTypes());
|
||||||
|
|
||||||
|
$server = Server::create()
|
||||||
|
->setDirectives($directives = []);
|
||||||
|
|
||||||
|
$this->assertSame($directives, $server->getDirectives());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testParse()
|
||||||
|
{
|
||||||
|
$server = Server::create();
|
||||||
|
$ast = $server->parse('{q}');
|
||||||
|
$this->assertInstanceOf('GraphQL\Language\AST\DocumentNode', $ast);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$server->parse('{q');
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (\GraphQL\Error\SyntaxError $e) {
|
||||||
|
$this->assertContains('{q', $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidate()
|
||||||
|
{
|
||||||
|
$server = Server::create()
|
||||||
|
->setQueryType(new ObjectType(['name' => 'Q', 'fields' => []]));
|
||||||
|
|
||||||
|
$ast = $server->parse('{q}');
|
||||||
|
$errors = $server->validate($ast);
|
||||||
|
|
||||||
|
$this->assertInternalType('array', $errors);
|
||||||
|
$this->assertNotEmpty($errors);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$server = Server::create();
|
||||||
|
$server->validate($ast);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot validate, schema contains errors: Schema query must be Object Type but got: NULL',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPromiseAdapter()
|
||||||
|
{
|
||||||
|
$adapter1 = new SyncPromiseAdapter();
|
||||||
|
$adapter2 = new SyncPromiseAdapter();
|
||||||
|
|
||||||
|
$server = Server::create()
|
||||||
|
->setPromiseAdapter($adapter1);
|
||||||
|
|
||||||
|
$this->assertSame($adapter1, $server->getPromiseAdapter());
|
||||||
|
$server->setPromiseAdapter($adapter1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$server->setPromiseAdapter($adapter2);
|
||||||
|
$this->fail('Expected exception not thrown');
|
||||||
|
} catch (InvariantViolation $e) {
|
||||||
|
$this->assertEquals(
|
||||||
|
'Cannot set promise adapter: Different adapter is already set',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidationRules()
|
||||||
|
{
|
||||||
|
$rules = [];
|
||||||
|
$server = Server::create()
|
||||||
|
->setValidationRules($rules);
|
||||||
|
|
||||||
|
$this->assertSame($rules, $server->getValidationRules());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExecuteQuery()
|
||||||
|
{
|
||||||
|
$called = false;
|
||||||
|
$queryType = new ObjectType([
|
||||||
|
'name' => 'Q',
|
||||||
|
'fields' => [
|
||||||
|
'field' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function($value, $args, $context, ResolveInfo $info) use (&$called) {
|
||||||
|
$called = true;
|
||||||
|
$this->assertEquals(null, $context);
|
||||||
|
$this->assertEquals(null, $value);
|
||||||
|
$this->assertEquals(null, $info->rootValue);
|
||||||
|
return 'ok';
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$server = Server::create()
|
||||||
|
->setQueryType($queryType);
|
||||||
|
|
||||||
|
$result = $server->executeQuery('{field}');
|
||||||
|
$this->assertEquals(true, $called);
|
||||||
|
$this->assertInstanceOf('GraphQL\Executor\ExecutionResult', $result);
|
||||||
|
$this->assertEquals(['data' => ['field' => 'ok']], $result->toArray());
|
||||||
|
|
||||||
|
$called = false;
|
||||||
|
$contextValue = new \stdClass();
|
||||||
|
$rootValue = new \stdClass();
|
||||||
|
|
||||||
|
$queryType = new ObjectType([
|
||||||
|
'name' => 'QueryType',
|
||||||
|
'fields' => [
|
||||||
|
'field' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function($value, $args, $context, ResolveInfo $info) use (&$called, $contextValue, $rootValue) {
|
||||||
|
$called = true;
|
||||||
|
$this->assertSame($rootValue, $value);
|
||||||
|
$this->assertSame($contextValue, $context);
|
||||||
|
$this->assertEquals($rootValue, $info->rootValue);
|
||||||
|
return 'ok';
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$server = Server::create()
|
||||||
|
->setQueryType($queryType)
|
||||||
|
->setRootValue($rootValue)
|
||||||
|
->setContext($contextValue);
|
||||||
|
|
||||||
|
$result = $server->executeQuery('{field}');
|
||||||
|
$this->assertEquals(true, $called);
|
||||||
|
$this->assertInstanceOf('GraphQL\Executor\ExecutionResult', $result);
|
||||||
|
$this->assertEquals(['data' => ['field' => 'ok']], $result->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDebugPhpErrors()
|
||||||
|
{
|
||||||
|
$queryType = new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => [
|
||||||
|
'err' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function() {
|
||||||
|
trigger_error('notice', E_USER_NOTICE);
|
||||||
|
return 'err';
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$server = Server::create()
|
||||||
|
->setDebug(0)
|
||||||
|
->setQueryType($queryType);
|
||||||
|
|
||||||
|
$prevEnabled = \PHPUnit_Framework_Error_Notice::$enabled;
|
||||||
|
\PHPUnit_Framework_Error_Notice::$enabled = false;
|
||||||
|
$result = @$server->executeQuery('{err}');
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'data' => ['err' => 'err']
|
||||||
|
];
|
||||||
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
|
$server->setDebug(Server::DEBUG_PHP_ERRORS);
|
||||||
|
$result = @$server->executeQuery('{err}');
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'data' => ['err' => 'err'],
|
||||||
|
'extensions' => [
|
||||||
|
'phpErrors' => [
|
||||||
|
[
|
||||||
|
'message' => 'notice',
|
||||||
|
'severity' => 1024,
|
||||||
|
// 'trace' => [...]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertArraySubset($expected, $result->toArray());
|
||||||
|
|
||||||
|
$server->setPhpErrorFormatter(function(\ErrorException $e) {
|
||||||
|
return ['test' => $e->getMessage()];
|
||||||
|
});
|
||||||
|
|
||||||
|
$result = $server->executeQuery('{err}');
|
||||||
|
$expected = [
|
||||||
|
'data' => ['err' => 'err'],
|
||||||
|
'extensions' => [
|
||||||
|
'phpErrors' => [
|
||||||
|
[
|
||||||
|
'test' => 'notice'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
|
\PHPUnit_Framework_Error_Notice::$enabled = $prevEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDebugExceptions()
|
||||||
|
{
|
||||||
|
$queryType = new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => [
|
||||||
|
'withException' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function() {
|
||||||
|
throw new \Exception("Error");
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$server = Server::create()
|
||||||
|
->setDebug(0)
|
||||||
|
->setQueryType($queryType);
|
||||||
|
|
||||||
|
$result = $server->executeQuery('{withException}');
|
||||||
|
$expected = [
|
||||||
|
'data' => [
|
||||||
|
'withException' => null
|
||||||
|
],
|
||||||
|
'errors' => [[
|
||||||
|
'message' => 'Error',
|
||||||
|
'path' => ['withException'],
|
||||||
|
'locations' => [[
|
||||||
|
'line' => 1,
|
||||||
|
'column' => 2
|
||||||
|
]]
|
||||||
|
]]
|
||||||
|
];
|
||||||
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
|
||||||
|
$server->setDebug(Server::DEBUG_EXCEPTIONS);
|
||||||
|
$result = $server->executeQuery('{withException}');
|
||||||
|
|
||||||
|
$expected['errors'][0]['exception'] = ['message' => 'Error', 'trace' => []];
|
||||||
|
$this->assertArraySubset($expected, $result->toArray());
|
||||||
|
|
||||||
|
$server->setExceptionFormatter(function(\Exception $e) {
|
||||||
|
return ['test' => $e->getMessage()];
|
||||||
|
});
|
||||||
|
|
||||||
|
$result = $server->executeQuery('{withException}');
|
||||||
|
$expected['errors'][0]['exception'] = ['test' => 'Error'];
|
||||||
|
$this->assertEquals($expected, $result->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHandleRequest()
|
||||||
|
{
|
||||||
|
$mock = $this->getMock('GraphQL\Server', ['readInput', 'produceOutput']);
|
||||||
|
$mock->method('readInput')
|
||||||
|
->will($this->returnValue(json_encode(['query' => '{err}'])));
|
||||||
|
|
||||||
|
$output = null;
|
||||||
|
$mock->method('produceOutput')
|
||||||
|
->will($this->returnCallback(function($a1, $a2) use (&$output) {
|
||||||
|
$output = func_get_args();
|
||||||
|
}));
|
||||||
|
|
||||||
|
/** @var $mock Server */
|
||||||
|
$mock->handleRequest();
|
||||||
|
|
||||||
|
$this->assertInternalType('array', $output);
|
||||||
|
$this->assertEquals(['errors' => [['message' => 'Unexpected Error']]], $output[0]);
|
||||||
|
$this->assertEquals(500, $output[1]);
|
||||||
|
|
||||||
|
$output = null;
|
||||||
|
$mock->setUnexpectedErrorMessage($newErr = 'Hey! Something went wrong!');
|
||||||
|
$mock->setUnexpectedErrorStatus(501);
|
||||||
|
$mock->handleRequest();
|
||||||
|
|
||||||
|
$this->assertInternalType('array', $output);
|
||||||
|
$this->assertEquals(['errors' => [['message' => $newErr]]], $output[0]);
|
||||||
|
$this->assertEquals(501, $output[1]);
|
||||||
|
|
||||||
|
$mock->setQueryType(new ObjectType([
|
||||||
|
'name' => 'Query',
|
||||||
|
'fields' => [
|
||||||
|
'test' => [
|
||||||
|
'type' => Type::string(),
|
||||||
|
'resolve' => function() {
|
||||||
|
return 'ok';
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]));
|
||||||
|
|
||||||
|
$_REQUEST = ['query' => '{err}'];
|
||||||
|
$output = null;
|
||||||
|
$mock->handleRequest();
|
||||||
|
$this->assertInternalType('array', $output);
|
||||||
|
|
||||||
|
$expectedOutput = [
|
||||||
|
['errors' => [[
|
||||||
|
'message' => 'Cannot query field "err" on type "Query".',
|
||||||
|
'locations' => [[
|
||||||
|
'line' => 1,
|
||||||
|
'column' => 2
|
||||||
|
]]
|
||||||
|
]]],
|
||||||
|
200
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expectedOutput, $output);
|
||||||
|
|
||||||
|
$output = null;
|
||||||
|
$_SERVER['CONTENT_TYPE'] = 'application/json';
|
||||||
|
$_REQUEST = [];
|
||||||
|
$mock->handleRequest();
|
||||||
|
|
||||||
|
$this->assertInternalType('array', $output);
|
||||||
|
$this->assertEquals($expectedOutput, $output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user