Skip to content

Commit 9e77b92

Browse files
lrafeeiTimPansino
andcommitted
GraphQL Strawberry Testing (#360)
* Start strawberry GraphQL testing * Fix Strawberry GraphQL tests * Strawberry tox config * Strawberry Testing Updates * More testing fixes * Linting and Formatting Co-authored-by: Tim Pansino <[email protected]>
1 parent c88e437 commit 9e77b92

File tree

10 files changed

+940
-9
lines changed

10 files changed

+940
-9
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ include = '\.pyi?$'
66
profile = "black"
77

88
[tool.pylint.messages_control]
9-
disable = "B101,C0103,C0114,C0115,C0116,C0302,C0415,E0401,E1120,E122,E126,E127,E128,E203,E501,E722,R0201,R0205,R0801,R0903,R0912,R0913,R0914,R0915,R1725,W0212,W0223,W0603,W0613,W0703,W0706,W504,redefined-outer-name"
9+
disable = "B101,C0103,C0114,C0115,C0116,C0302,C0415,E0401,E1120,E122,E126,E127,E128,E203,E501,E722,R0201,R0205,R0801,R0903,R0912,R0913,R0914,R0915,R1725,W0212,W0223,W0603,W0613,W0703,W0706,W504,line-too-long,redefined-outer-name"
1010

1111
[tool.pylint.format]
1212
max-line-length = "120"

tests/framework_ariadne/_target_application.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def mutate(self, info, string):
104104
def resolve_type(obj, *args):
105105
if "isbn" in obj:
106106
return "Book"
107-
elif "issue" in obj:
107+
elif "issue" in obj: # pylint: disable=R1705
108108
return "Magazine"
109109

110110
return None

tests/framework_ariadne/test_application.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ def delay_import():
6767
return delay_import
6868

6969

70-
def example_middleware(next, root, info, **args):
70+
def example_middleware(next, root, info, **args): # pylint: disable=W0622
7171
return_value = next(root, info, **args)
7272
return return_value
7373

7474

75-
def error_middleware(next, root, info, **args):
75+
def error_middleware(next, root, info, **args): # pylint: disable=W0622
7676
raise RuntimeError("Runtime Error!")
7777

7878

@@ -249,7 +249,7 @@ def _test():
249249
from graphql import MiddlewareManager
250250

251251
ok, response = graphql_run(app, query, middleware=MiddlewareManager(error_middleware))
252-
assert response["errors"]
252+
assert not ok and response["errors"]
253253

254254
_test()
255255

@@ -297,7 +297,7 @@ def test_exception_in_resolver(app, graphql_run, field):
297297
@background_task()
298298
def _test():
299299
ok, response = graphql_run(app, query)
300-
assert response["errors"]
300+
assert not ok and response["errors"]
301301

302302
_test()
303303

@@ -353,7 +353,7 @@ def test_exception_in_validation(app, graphql_run, is_graphql_2, query, exc_clas
353353
@background_task()
354354
def _test():
355355
ok, response = graphql_run(app, query)
356-
assert response["errors"]
356+
assert not ok and response["errors"]
357357

358358
_test()
359359

tests/framework_graphene/test_application.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@ def delay_import():
6666
return delay_import
6767

6868

69-
def example_middleware(next, root, info, **args):
69+
def example_middleware(next, root, info, **args): #pylint: disable=W0622
7070
return_value = next(root, info, **args)
7171
return return_value
7272

7373

74-
def error_middleware(next, root, info, **args):
74+
def error_middleware(next, root, info, **args): #pylint: disable=W0622
7575
raise RuntimeError("Runtime Error!")
7676

7777

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# Copyright 2010 New Relic, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from typing import Union
16+
17+
import strawberry.mutation
18+
import strawberry.type
19+
from strawberry import Schema, field, union
20+
from strawberry.asgi import GraphQL
21+
from strawberry.schema.config import StrawberryConfig
22+
from strawberry.types.types import Optional
23+
24+
25+
@strawberry.type
26+
class Author:
27+
first_name: str
28+
last_name: str
29+
30+
31+
@strawberry.type
32+
class Book:
33+
id: int
34+
name: str
35+
isbn: str
36+
author: Author
37+
branch: str
38+
39+
40+
@strawberry.type
41+
class Magazine:
42+
id: int
43+
name: str
44+
issue: int
45+
branch: str
46+
47+
48+
@strawberry.type
49+
class Library:
50+
id: int
51+
branch: str
52+
magazine: list[Magazine]
53+
book: list[Book]
54+
55+
56+
Item = Union[Book, Magazine]
57+
58+
59+
Storage = list[str]
60+
61+
62+
authors = [
63+
Author(
64+
first_name="New",
65+
last_name="Relic",
66+
),
67+
Author(
68+
first_name="Bob",
69+
last_name="Smith",
70+
),
71+
Author(
72+
first_name="Leslie",
73+
last_name="Jones",
74+
),
75+
]
76+
77+
books = [
78+
Book(
79+
id=1,
80+
name="Python Agent: The Book",
81+
isbn="a-fake-isbn",
82+
author=authors[0],
83+
branch="riverside",
84+
),
85+
Book(
86+
id=2,
87+
name="Ollies for O11y: A Sk8er's Guide to Observability",
88+
isbn="a-second-fake-isbn",
89+
author=authors[1],
90+
branch="downtown",
91+
),
92+
Book(
93+
id=3,
94+
name="[Redacted]",
95+
isbn="a-third-fake-isbn",
96+
author=authors[2],
97+
branch="riverside",
98+
),
99+
]
100+
101+
magazines = [
102+
Magazine(id=1, name="Reli Updates Weekly", issue=1, branch="riverside"),
103+
Magazine(id=2, name="Reli: The Forgotten Years", issue=2, branch="downtown"),
104+
Magazine(id=3, name="Node Weekly", issue=1, branch="riverside"),
105+
]
106+
107+
108+
libraries = ["riverside", "downtown"]
109+
libraries = [
110+
Library(
111+
id=i + 1,
112+
branch=branch,
113+
magazine=[m for m in magazines if m.branch == branch],
114+
book=[b for b in books if b.branch == branch],
115+
)
116+
for i, branch in enumerate(libraries)
117+
]
118+
119+
storage = []
120+
121+
122+
def resolve_hello():
123+
return "Hello!"
124+
125+
126+
async def resolve_hello_async():
127+
return "Hello!"
128+
129+
130+
def resolve_echo(echo: str):
131+
return echo
132+
133+
134+
def resolve_library(index: int):
135+
return libraries[index]
136+
137+
138+
def resolve_storage_add(string: str):
139+
storage.add(string)
140+
return storage
141+
142+
143+
def resolve_storage():
144+
return storage
145+
146+
147+
def resolve_error():
148+
raise RuntimeError("Runtime Error!")
149+
150+
151+
def resolve_search(contains: str):
152+
search_books = [b for b in books if contains in b.name]
153+
search_magazines = [m for m in magazines if contains in m.name]
154+
return search_books + search_magazines
155+
156+
157+
@strawberry.type
158+
class Query:
159+
library: Library = field(resolver=resolve_library)
160+
hello: str = field(resolver=resolve_hello)
161+
hello_async: str = field(resolver=resolve_hello_async)
162+
search: list[Item] = field(resolver=resolve_search)
163+
echo: str = field(resolver=resolve_echo)
164+
storage: Storage = field(resolver=resolve_storage)
165+
error: Optional[str] = field(resolver=resolve_error)
166+
error_non_null: str = field(resolver=resolve_error)
167+
168+
def resolve_library(self, info, index):
169+
return libraries[index]
170+
171+
def resolve_storage(self, info):
172+
return storage
173+
174+
def resolve_search(self, info, contains):
175+
search_books = [b for b in books if contains in b.name]
176+
search_magazines = [m for m in magazines if contains in m.name]
177+
return search_books + search_magazines
178+
179+
def resolve_hello(self, info):
180+
return "Hello!"
181+
182+
def resolve_echo(self, info, echo):
183+
return echo
184+
185+
def resolve_error(self, info) -> str:
186+
raise RuntimeError("Runtime Error!")
187+
188+
189+
@strawberry.type
190+
class Mutation:
191+
@strawberry.mutation
192+
def storage_add(self, string: str) -> str:
193+
storage.append(string)
194+
return str(string)
195+
196+
197+
_target_application = Schema(query=Query, mutation=Mutation, config=StrawberryConfig(auto_camel_case=False))
198+
_target_asgi_application = GraphQL(_target_application)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright 2010 New Relic, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pytest
16+
import six
17+
from testing_support.fixtures import ( # noqa: F401; pylint: disable=W0611
18+
code_coverage_fixture,
19+
collector_agent_registration_fixture,
20+
collector_available_fixture,
21+
)
22+
23+
_coverage_source = [
24+
"newrelic.hooks.framework_graphql",
25+
]
26+
27+
code_coverage = code_coverage_fixture(source=_coverage_source)
28+
29+
_default_settings = {
30+
"transaction_tracer.explain_threshold": 0.0,
31+
"transaction_tracer.transaction_threshold": 0.0,
32+
"transaction_tracer.stack_trace_threshold": 0.0,
33+
"debug.log_data_collector_payloads": True,
34+
"debug.record_transaction_failure": True,
35+
}
36+
37+
collector_agent_registration = collector_agent_registration_fixture(
38+
app_name="Python Agent Test (framework_strawberry)",
39+
default_settings=_default_settings,
40+
)
41+
42+
43+
@pytest.fixture(scope="session")
44+
def app():
45+
from _target_application import _target_application
46+
47+
return _target_application
48+
49+
50+
if six.PY2:
51+
collect_ignore = ["test_application_async.py"]

0 commit comments

Comments
 (0)