graphql-engine/server/tests-py/test_v1alpha1_endpoint.py
Brandon Simmons 91aee7fdeb Test result ordering, add --accept test mode to automatically accept changed test cases
We add a new pytest flag `--accept` that will automatically write back
yaml files with updated responses. This makes it much easier and less
error-prone to update test cases when we expect output to change, or
when authoring new tests.

Second we make sure to test that we actually preserve the order of the
selection set when returning results. This is a "SHOULD" part of the
spec but seems pretty important and something that users will rely on.

To support both of the above we use ruamel.yaml which preserves a
certain amount of formatting and comments (so that --accept can work in
a failry ergonomic way), as well as ordering (so that when we write yaml
the order of keys has meaning that's preserved during parsing).

Use ruamel.yaml everywhere for consistency (since both libraries have
different quirks).

Quirks of ruamel.yaml:
- trailing whitespace in multiline strings in yaml files isn't written
  back out as we'd like: https://bitbucket.org/ruamel/yaml/issues/47/multiline-strings-being-changed-if-they
- formatting is only sort of preserved; ruamel e.g. normalizes
  indentation. Normally the diff is pretty clean though, and you can
  always just check in portions of your test file after --accept

fixup
2019-11-05 15:15:25 -06:00

156 lines
5.0 KiB
Python

import ruamel.yaml as yaml
import pytest
#from validate import check_query, test_forbidden_when_admin_secret_reqd, test_forbidden_webhook
from validate import check_query
import validate
from super_classes import DefaultTestSelectQueries
from context import GQLWsClient
class TestV1Alpha1GraphQLErrors(DefaultTestSelectQueries):
@classmethod
def dir(cls):
return 'queries/graphql_query/v1alpha1/errors'
def test_v1alpha1_authorization_error(self, hge_ctx):
gql_query = """
query {
author {
id
name
}
}
"""
http_conf = {
'url': '/v1alpha1/graphql',
'status': 200,
'query': {'query': gql_query},
}
if hge_ctx.hge_key is not None and hge_ctx.hge_webhook is None and hge_ctx.hge_jwt_key is None:
# Test whether it is forbidden when incorrect/no admin_secret is specified
validate.test_forbidden_when_admin_secret_reqd(hge_ctx, http_conf)
elif hge_ctx.hge_webhook is not None:
if not hge_ctx.webhook_insecure:
# Check whether the output is also forbidden when webhook returns forbidden
validate.test_forbidden_webhook(hge_ctx, http_conf)
else:
assert True
@pytest.mark.parametrize('transport', ['http', 'websocket'])
def test_v1alpha1_validation_error(self, hge_ctx, transport):
gql_query = """
query {
author {
id
name
notPresentCol
}
}
"""
http_conf = {
'url': '/v1alpha1/graphql',
'status': 400,
'query': {'query': gql_query},
'response': {
"errors": [{
"extensions": {
"path": "$.selectionSet.author.selectionSet.notPresentCol",
"code": "validation-failed"
},
"message": "field \"notPresentCol\" not found in type: 'author'"
}]
}
}
ws_conf = {
'url': '/v1alpha1/graphql',
'query': {'query': gql_query},
'response': {
"path": "$.selectionSet.author.selectionSet.notPresentCol",
"code": "validation-failed",
"error": "field \"notPresentCol\" not found in type: 'author'"
}
}
if transport == 'http':
check_query(hge_ctx, http_conf, transport)
elif transport == 'websocket':
check_query(hge_ctx, ws_conf, transport)
@pytest.mark.parametrize('transport', ['http', 'websocket'])
def test_v1alpha1_execution_error(self, hge_ctx, transport):
mutation = """
mutation {
insert_article (objects: [
{
title: "test 3"
content: "test 3 content"
author_id: 44
is_published: false
}
]) {
returning {
id
}
}
}
"""
http_conf = {
'url': '/v1alpha1/graphql',
'status': 400,
'query': {'query': mutation},
'response': {
"errors": [{
"extensions": {
"path": "$.selectionSet.insert_article.args.objects",
"code": "constraint-violation"
},
"message": "Foreign key violation. insert or update on table \"article\" violates foreign key constraint \"article_author_id_fkey\""
}]
}
}
ws_conf = {
'url': '/v1alpha1/graphql',
'query': {'query': mutation},
'response': {
'data': None,
"errors": [{
"path": "$.selectionSet.insert_article.args.objects",
"error": "Foreign key violation. insert or update on table \"article\" violates foreign key constraint \"article_author_id_fkey\"",
"code": "constraint-violation"
}]
}
}
if transport == 'http':
check_query(hge_ctx, http_conf, transport)
elif transport == 'websocket':
check_query(hge_ctx, ws_conf, transport)
def test_v1alpha1_ws_start_error(self, hge_ctx):
ws_client = GQLWsClient(hge_ctx, '/v1alpha1/graphql')
query = {'query': '{ author { name } }'}
frame = {
'id': '1',
'type': 'start',
'payload': query
}
ws_client.ws_active_query_ids.add('1')
ws_client.send(frame)
resp = ws_client.get_ws_query_event('1', 10)
print(resp)
assert 'type' in resp
assert resp['type'] == 'error'
assert 'payload' in resp
assert resp['payload'] == {
'path': '$',
'error': 'start received before the connection is initialised',
'code': 'start-failed'
}