graphql-engine/server/tests-py/test_actions.py
Rakesh Emmadi f80b69e931
few actions' fixes and improvements (fix #3977, #4061 & close #4021) (#4109)
* add 'ID' to default scalars for custom types, fix #4061

* preserve cookie headers from sync action webhook, close #4021

* validate action webhook response to conform to output type, fix #3977

* fix tests, don't run actions' tests on PG version < 10

* update CHANGELOG.md

* no-op refactor, use types from http-network more

Co-authored-by: Vamshi Surabhi <0x777@users.noreply.github.com>
2020-03-20 12:16:45 +05:30

300 lines
8.6 KiB
Python

#!/usr/bin/env python3
import pytest
import time
from validate import check_query_f, check_query
"""
TODO:- Test Actions metadata
"""
use_action_fixtures = pytest.mark.usefixtures(
"actions_fixture",
'per_class_db_schema_for_mutation_tests',
'per_method_db_data_for_mutation_tests'
)
@pytest.mark.parametrize("transport", ['http', 'websocket'])
@use_action_fixtures
class TestActionsSyncWebsocket:
@classmethod
def dir(cls):
return 'queries/actions/sync'
def test_create_user_fail(self, hge_ctx, transport):
check_query_f(hge_ctx, self.dir() + '/create_user_fail.yaml', transport)
def test_create_user_success(self, hge_ctx, transport):
check_query_f(hge_ctx, self.dir() + '/create_user_success.yaml', transport)
def test_create_users_fail(self, hge_ctx, transport):
check_query_f(hge_ctx, self.dir() + '/create_users_fail.yaml', transport)
def test_create_users_success(self, hge_ctx, transport):
check_query_f(hge_ctx, self.dir() + '/create_users_success.yaml', transport)
@use_action_fixtures
class TestActionsSync:
@classmethod
def dir(cls):
return 'queries/actions/sync'
def test_invalid_webhook_response(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/invalid_webhook_response.yaml')
def test_expecting_object_response(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/expecting_object_response.yaml')
def test_expecting_array_response(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/expecting_array_response.yaml')
# Webhook response validation tests. See https://github.com/hasura/graphql-engine/issues/3977
def test_mirror_action_not_null(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/mirror_action_not_null.yaml')
def test_mirror_action_unexpected_field(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/mirror_action_unexpected_field.yaml')
def test_mirror_action_no_field(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/mirror_action_no_field.yaml')
def test_mirror_action_success(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/mirror_action_success.yaml')
def mk_headers_with_secret(hge_ctx, headers={}):
admin_secret = hge_ctx.hge_key
if admin_secret:
headers['X-Hasura-Admin-Secret'] = admin_secret
return headers
@use_action_fixtures
class TestActionsSyncResponseHeaders:
@classmethod
def dir(cls):
return 'queries/actions/sync'
# See https://github.com/hasura/graphql-engine/issues/4021
def test_set_cookie_header(self, hge_ctx):
mutation = '''
mutation {
create_user(email: "clarke@gmail.com", name: "Clarke"){
id
}
}
'''
query = {
'query': mutation,
'variables': {}
}
status, resp, resp_headers = hge_ctx.anyq('/v1/graphql', query, mk_headers_with_secret(hge_ctx))
assert status == 200, resp
assert 'data' in resp, resp
assert ('Set-Cookie' in resp_headers and
resp_headers['Set-Cookie'] == 'abcd'), resp_headers
@use_action_fixtures
class TestActionsAsync:
@classmethod
def dir(cls):
return 'queries/actions/async'
def test_create_user_fail(self, hge_ctx):
graphql_mutation = '''
mutation {
create_user(email: "random-email", name: "Clarke")
}
'''
query = {
'query': graphql_mutation,
'variables': {}
}
status, resp, _ = hge_ctx.anyq('/v1/graphql', query, mk_headers_with_secret(hge_ctx))
assert status == 200, resp
assert 'data' in resp
action_id = resp['data']['create_user']
time.sleep(3)
query_async = '''
query ($action_id: uuid!){
create_user(id: $action_id){
id
errors
}
}
'''
query = {
'query': query_async,
'variables': {
'action_id': action_id
}
}
response = {
'data': {
'create_user': {
'id': action_id,
'errors': {
'code': 'invalid-email',
'path': '$',
'error': 'Given email address is not valid'
}
}
}
}
conf = {
'url': '/v1/graphql',
'headers': {},
'query': query,
'status': 200,
'response': response
}
check_query(hge_ctx, conf)
def test_create_user_success(self, hge_ctx):
graphql_mutation = '''
mutation {
create_user(email: "clarke@hasura.io", name: "Clarke")
}
'''
query = {
'query': graphql_mutation,
'variables': {}
}
status, resp, _ = hge_ctx.anyq('/v1/graphql', query, mk_headers_with_secret(hge_ctx))
assert status == 200, resp
assert 'data' in resp
action_id = resp['data']['create_user']
time.sleep(3)
query_async = '''
query ($action_id: uuid!){
create_user(id: $action_id){
__typename
id
output {
__typename
id
user {
__typename
name
email
is_admin
}
}
}
}
'''
query = {
'query': query_async,
'variables': {
'action_id': action_id
}
}
response = {
'data': {
'create_user': {
'__typename': 'create_user',
'id': action_id,
'output': {
'__typename': 'UserId',
'id': 1,
'user': {
'__typename': 'user',
'name': 'Clarke',
'email': 'clarke@hasura.io',
'is_admin': False
}
}
}
}
}
conf = {
'url': '/v1/graphql',
'headers': {},
'query': query,
'status': 200,
'response': response
}
check_query(hge_ctx, conf)
def test_create_user_roles(self, hge_ctx):
graphql_mutation = '''
mutation {
create_user(email: "blake@hasura.io", name: "Blake")
}
'''
query = {
'query': graphql_mutation,
'variables': {}
}
headers_user_1 = mk_headers_with_secret(hge_ctx, {
'X-Hasura-Role': 'user',
'X-Hasura-User-Id': '1'
})
# create action with user-id 1
status, resp, headers = hge_ctx.anyq('/v1/graphql', query, headers_user_1)
assert status == 200, resp
assert 'data' in resp
action_id = resp['data']['create_user']
time.sleep(3)
query_async = '''
query ($action_id: uuid!){
create_user(id: $action_id){
id
output {
id
}
}
}
'''
query = {
'query': query_async,
'variables': {
'action_id': action_id
}
}
headers_user_2 = mk_headers_with_secret(hge_ctx, {
'X-Hasura-Role': 'user',
'X-Hasura-User-Id': '2'
})
conf_user_2 = {
'url': '/v1/graphql',
'headers': headers_user_2,
'query': query,
'status': 200,
'response': {
'data': {
'create_user': None # User 2 shouldn't able to access the action
}
}
}
# Query the action as user-id 2
# Make request without auth using admin_secret
check_query(hge_ctx, conf_user_2, add_auth = False)
conf_user_1 = {
'url': '/v1/graphql',
'headers': headers_user_1,
'query': query,
'status': 200,
'response': {
'data': {
'create_user': {
'id': action_id,
'output': {
'id': 1
}
}
}
}
}
# Query the action as user-id 1
# Make request without auth using admin_secret
check_query(hge_ctx, conf_user_1, add_auth = False)