From debd05314a09a1791c92aa010e0e3ff2a4a4c094 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Tue, 22 May 2018 10:16:41 -0700 Subject: [PATCH 1/3] Create dedicated test file for middleware (test_middleware.py) and add test that pins down the order that middleware is executed in --- .gitignore | 1 + graphql/execution/middleware.py | 2 +- graphql/execution/tests/test_executor.py | 105 -------------- graphql/execution/tests/test_middleware.py | 157 +++++++++++++++++++++ 4 files changed, 159 insertions(+), 106 deletions(-) create mode 100644 graphql/execution/tests/test_middleware.py diff --git a/.gitignore b/.gitignore index 74b41897..af2acb26 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ htmlcov/ nosetests.xml coverage.xml *,cover +.pytest_cache/ # Translations *.mo diff --git a/graphql/execution/middleware.py b/graphql/execution/middleware.py index 22bcfd32..09de12e1 100644 --- a/graphql/execution/middleware.py +++ b/graphql/execution/middleware.py @@ -39,7 +39,7 @@ def get_middleware_resolvers(middlewares): yield getattr(middleware, MIDDLEWARE_RESOLVER_FUNCTION) -def middleware_chain(func, middlewares, wrap_in_promise): +def middleware_chain(func, middlewares, wrap_in_promise=True): if not middlewares: return func if wrap_in_promise: diff --git a/graphql/execution/tests/test_executor.py b/graphql/execution/tests/test_executor.py index cc107362..fa5b1413 100644 --- a/graphql/execution/tests/test_executor.py +++ b/graphql/execution/tests/test_executor.py @@ -565,111 +565,6 @@ def resolver(*_): "An error occurred while resolving field Query.foo") -def test_middleware(): - doc = '''{ - ok - not_ok - }''' - - class Data(object): - - def ok(self): - return 'ok' - - def not_ok(self): - return 'not_ok' - - doc_ast = parse(doc) - - Type = GraphQLObjectType('Type', { - 'ok': GraphQLField(GraphQLString), - 'not_ok': GraphQLField(GraphQLString), - }) - - def reversed_middleware(next, *args, **kwargs): - p = next(*args, **kwargs) - return p.then(lambda x: x[::-1]) - - middlewares = MiddlewareManager(reversed_middleware) - result = execute(GraphQLSchema(Type), doc_ast, - Data(), middleware=middlewares) - assert result.data == {'ok': 'ko', 'not_ok': 'ko_ton'} - - -def test_middleware_class(): - doc = '''{ - ok - not_ok - }''' - - class Data(object): - - def ok(self): - return 'ok' - - def not_ok(self): - return 'not_ok' - - doc_ast = parse(doc) - - Type = GraphQLObjectType('Type', { - 'ok': GraphQLField(GraphQLString), - 'not_ok': GraphQLField(GraphQLString), - }) - - class MyMiddleware(object): - def resolve(self, next, *args, **kwargs): - p = next(*args, **kwargs) - return p.then(lambda x: x[::-1]) - - middlewares = MiddlewareManager(MyMiddleware()) - result = execute(GraphQLSchema(Type), doc_ast, - Data(), middleware=middlewares) - assert result.data == {'ok': 'ko', 'not_ok': 'ko_ton'} - - -def test_middleware_skip_promise_wrap(): - doc = '''{ - ok - not_ok - }''' - - class Data(object): - - def ok(self): - return 'ok' - - def not_ok(self): - return 'not_ok' - - doc_ast = parse(doc) - - Type = GraphQLObjectType('Type', { - 'ok': GraphQLField(GraphQLString), - 'not_ok': GraphQLField(GraphQLString), - }) - - class MyPromiseMiddleware(object): - def resolve(self, next, *args, **kwargs): - return Promise.resolve(next(*args, **kwargs)) - - class MyEmptyMiddleware(object): - def resolve(self, next, *args, **kwargs): - return next(*args, **kwargs) - - middlewares_with_promise = MiddlewareManager( - MyPromiseMiddleware(), wrap_in_promise=False) - middlewares_without_promise = MiddlewareManager( - MyEmptyMiddleware(), wrap_in_promise=False) - - result1 = execute(GraphQLSchema(Type), doc_ast, Data(), - middleware=middlewares_with_promise) - result2 = execute(GraphQLSchema(Type), doc_ast, Data(), - middleware=middlewares_without_promise) - assert result1.data == result2.data and result1.data == { - 'ok': 'ok', 'not_ok': 'not_ok'} - - def test_executor_properly_propogates_path_data(mocker): time_mock = mocker.patch('time.time') time_mock.side_effect = range(0, 10000) diff --git a/graphql/execution/tests/test_middleware.py b/graphql/execution/tests/test_middleware.py new file mode 100644 index 00000000..4e4d98f5 --- /dev/null +++ b/graphql/execution/tests/test_middleware.py @@ -0,0 +1,157 @@ +from graphql.execution.middleware import middleware_chain +from graphql.execution.middleware import get_middleware_resolvers +from graphql.language.parser import parse +from graphql.execution import MiddlewareManager, execute +from graphql.type import (GraphQLArgument, GraphQLBoolean, GraphQLField, + GraphQLInt, GraphQLList, GraphQLObjectType, + GraphQLSchema, GraphQLString, GraphQLNonNull, GraphQLID) +from promise import Promise + + +def test_middleware(): + doc = '''{ + ok + not_ok + }''' + + class Data(object): + + def ok(self): + return 'ok' + + def not_ok(self): + return 'not_ok' + + doc_ast = parse(doc) + + Type = GraphQLObjectType('Type', { + 'ok': GraphQLField(GraphQLString), + 'not_ok': GraphQLField(GraphQLString), + }) + + def reversed_middleware(next, *args, **kwargs): + p = next(*args, **kwargs) + return p.then(lambda x: x[::-1]) + + middlewares = MiddlewareManager(reversed_middleware) + result = execute(GraphQLSchema(Type), doc_ast, + Data(), middleware=middlewares) + assert result.data == {'ok': 'ko', 'not_ok': 'ko_ton'} + + +def test_middleware_class(): + doc = '''{ + ok + not_ok + }''' + + class Data(object): + + def ok(self): + return 'ok' + + def not_ok(self): + return 'not_ok' + + doc_ast = parse(doc) + + Type = GraphQLObjectType('Type', { + 'ok': GraphQLField(GraphQLString), + 'not_ok': GraphQLField(GraphQLString), + }) + + class MyMiddleware(object): + def resolve(self, next, *args, **kwargs): + p = next(*args, **kwargs) + return p.then(lambda x: x[::-1]) + + middlewares = MiddlewareManager(MyMiddleware()) + result = execute(GraphQLSchema(Type), doc_ast, + Data(), middleware=middlewares) + assert result.data == {'ok': 'ko', 'not_ok': 'ko_ton'} + + +def test_middleware_skip_promise_wrap(): + doc = '''{ + ok + not_ok + }''' + + class Data(object): + + def ok(self): + return 'ok' + + def not_ok(self): + return 'not_ok' + + doc_ast = parse(doc) + + Type = GraphQLObjectType('Type', { + 'ok': GraphQLField(GraphQLString), + 'not_ok': GraphQLField(GraphQLString), + }) + + class MyPromiseMiddleware(object): + def resolve(self, next, *args, **kwargs): + return Promise.resolve(next(*args, **kwargs)) + + class MyEmptyMiddleware(object): + def resolve(self, next, *args, **kwargs): + return next(*args, **kwargs) + + middlewares_with_promise = MiddlewareManager( + MyPromiseMiddleware(), wrap_in_promise=False) + middlewares_without_promise = MiddlewareManager( + MyEmptyMiddleware(), wrap_in_promise=False) + + result1 = execute(GraphQLSchema(Type), doc_ast, Data(), + middleware=middlewares_with_promise) + result2 = execute(GraphQLSchema(Type), doc_ast, Data(), + middleware=middlewares_without_promise) + assert result1.data == result2.data and result1.data == { + 'ok': 'ok', 'not_ok': 'not_ok'} + + +def test_middleware_chain(capsys): + + class CharPrintingMiddleware(object): + def __init__(self, char): + self.char = char + + def resolve(self, next, *args, **kwargs): + print(f'resolve() called for middleware {self.char}') + return next(*args, **kwargs).then( + lambda x: print(f'then() for {self.char}') + ) + + middlewares = [ + CharPrintingMiddleware('a'), + CharPrintingMiddleware('b'), + CharPrintingMiddleware('c'), + ] + + middlewares_resolvers = get_middleware_resolvers(middlewares) + + def func(): return + + chain_iter = middleware_chain(func, middlewares_resolvers) + + assert_stdout(capsys, "") + + chain_iter() + + expected_stdout = ( + 'resolve() called for middleware c\n' + 'resolve() called for middleware b\n' + 'resolve() called for middleware a\n' + 'then() for a\n' + 'then() for b\n' + 'then() for c\n' + ) + assert_stdout(capsys, expected_stdout) + + +def assert_stdout(capsys, expected_stdout): + captured = capsys.readouterr() + assert captured.out == expected_stdout \ No newline at end of file From 9f648287edb82330277ed606de333a41929f3c4c Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Tue, 22 May 2018 10:24:36 -0700 Subject: [PATCH 2/3] Make py2 compatible by importing print_function from __future__ --- graphql/execution/tests/test_middleware.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/graphql/execution/tests/test_middleware.py b/graphql/execution/tests/test_middleware.py index 4e4d98f5..e906c089 100644 --- a/graphql/execution/tests/test_middleware.py +++ b/graphql/execution/tests/test_middleware.py @@ -1,10 +1,12 @@ -from graphql.execution.middleware import middleware_chain -from graphql.execution.middleware import get_middleware_resolvers -from graphql.language.parser import parse +from __future__ import print_function + from graphql.execution import MiddlewareManager, execute +from graphql.execution.middleware import (get_middleware_resolvers, + middleware_chain) +from graphql.language.parser import parse from graphql.type import (GraphQLArgument, GraphQLBoolean, GraphQLField, - GraphQLInt, GraphQLList, GraphQLObjectType, - GraphQLSchema, GraphQLString, GraphQLNonNull, GraphQLID) + GraphQLID, GraphQLInt, GraphQLList, GraphQLNonNull, + GraphQLObjectType, GraphQLSchema, GraphQLString) from promise import Promise @@ -120,9 +122,9 @@ def __init__(self, char): self.char = char def resolve(self, next, *args, **kwargs): - print(f'resolve() called for middleware {self.char}') + print("resolve() called for middleware {}".format(self.char)) return next(*args, **kwargs).then( - lambda x: print(f'then() for {self.char}') + lambda x: print("then() for {}".format(self.char)) ) middlewares = [ @@ -154,4 +156,4 @@ def func(): return def assert_stdout(capsys, expected_stdout): captured = capsys.readouterr() - assert captured.out == expected_stdout \ No newline at end of file + assert captured.out == expected_stdout From 4d6aa6a359a4628f5850f2af63c4367f0239421a Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 13 Jul 2018 10:29:30 -0700 Subject: [PATCH 3/3] Make mypy happy by fixing type annotation --- graphql/execution/tests/test_middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphql/execution/tests/test_middleware.py b/graphql/execution/tests/test_middleware.py index 5592403c..9715288d 100644 --- a/graphql/execution/tests/test_middleware.py +++ b/graphql/execution/tests/test_middleware.py @@ -143,7 +143,7 @@ def resolve(self, next, *args, **kwargs): def test_middleware_chain(capsys): - # type: () -> None + # type: (Any) -> None class CharPrintingMiddleware(object): def __init__(self, char): # type: (str) -> None