2020-02-13 20:38:23 +03:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
import time
|
|
|
|
|
2022-10-21 20:32:58 +03:00
|
|
|
from conftest import use_action_fixtures, extract_server_address_from
|
server/tests-py: Start webhook.py inside the test harness.
We use a helper service to start a webhook-based authentication service for some tests. This moves the initialization of the service out of _test-server.sh_ and into the Python test harness, as a fixture.
In order to do this, I had to make a few changes. The main deviation is that we no longer run _all_ tests against an HGE with this authentication service, just a few (those in _test_webhook.py_). Because this reduced coverage, I have added some more tests there, which actually cover some areas not exacerbated elsewhere (mainly trying to use webhook credentials to talk to an admin-only endpoint).
The webhook service can run both with and without TLS, and decide whether it's necessary to skip one of these based on the arguments passed and how HGE is started, according to the following logic:
* If a TLS CA certificate is passed in, it will run with TLS, otherwise it will skip it.
* If HGE was started externally and a TLS certificate is provided, it will skip running without TLS, as it will assume that HGE was configured to talk to a webhook over HTTPS.
* Some tests should only be run with TLS; this is marked with a `tls_webhook_server` marker.
* Some tests should only be run _without_ TLS; this is marked with a `no_tls_webhook_server` marker.
The actual parameterization of the webhook service configuration is done through test subclasses, because normal pytest parameterization doesn't work with the `hge_fixture_env` hack that we use. Because `hge_fixture_env` is not a sanctioned way of conveying data between fixtures (and, unfortunately, there isn't a sanctioned way of doing this when the fixtures in question may not know about each other directly), parameterizing the `webhook_server` fixture doesn't actually parameterize `hge_server` properly. Subclassing forces this to work correctly.
The certificate generation is moved to a Python fixture, so that we don't have to revoke the CA certificate for _test_webhook_insecure.py_; we can just generate a bogus certificate instead. The CA certificate is still generated in the _test-server.sh_ script, as it needs to be installed into the OS certificate store.
Interestingly, the CA certificate installation wasn't actually working, because the certificates were written to the wrong location. This didn't cause any failures, as we weren't actually testing this behavior. This is now fixed with the other changes.
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6363
GitOrigin-RevId: 0f277d374daa64f657257ed2a4c2057c74b911db
2022-10-20 21:58:36 +03:00
|
|
|
from remote_server import NodeGraphQL
|
|
|
|
from validate import check_query_f, check_query, get_conf_f
|
2020-02-13 20:38:23 +03:00
|
|
|
|
|
|
|
"""
|
|
|
|
TODO:- Test Actions metadata
|
|
|
|
"""
|
|
|
|
|
2022-09-28 12:19:47 +03:00
|
|
|
@pytest.fixture(scope='class')
|
|
|
|
@pytest.mark.early
|
2023-04-25 15:49:31 +03:00
|
|
|
def graphql_service(worker_id: str, hge_fixture_env: dict[str, str]):
|
2022-10-21 20:32:58 +03:00
|
|
|
(_, port) = extract_server_address_from('GRAPHQL_SERVICE_HANDLER')
|
2023-04-25 15:49:31 +03:00
|
|
|
server = NodeGraphQL(worker_id, 'remote_schemas/nodejs/actions_remote_join_schema.js', port=port)
|
2022-10-21 20:32:58 +03:00
|
|
|
server.start()
|
|
|
|
print(f'{graphql_service.__name__} server started on {server.url}')
|
|
|
|
hge_fixture_env['GRAPHQL_SERVICE_HANDLER'] = server.url
|
|
|
|
yield server
|
|
|
|
server.stop()
|
2020-06-05 15:03:18 +03:00
|
|
|
|
|
|
|
|
|
|
|
use_action_fixtures_with_remote_joins = pytest.mark.usefixtures(
|
|
|
|
"graphql_service",
|
|
|
|
"actions_fixture",
|
|
|
|
"per_class_db_schema_for_mutation_tests",
|
|
|
|
"per_method_db_data_for_mutation_tests"
|
|
|
|
)
|
|
|
|
|
2021-03-31 13:39:01 +03:00
|
|
|
@pytest.mark.parametrize("transport", ['websocket'])
|
2020-02-13 20:38:23 +03:00
|
|
|
@use_action_fixtures
|
2020-03-20 09:46:45 +03:00
|
|
|
class TestActionsSyncWebsocket:
|
2020-02-13 20:38:23 +03:00
|
|
|
|
|
|
|
@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)
|
|
|
|
|
2021-01-18 09:56:25 +03:00
|
|
|
def test_create_user_relationship(self, hge_ctx, transport):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/create_user_relationship.yaml', transport)
|
|
|
|
|
|
|
|
def test_create_user_relationship(self, hge_ctx, transport):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/create_user_relationship_fail.yaml', transport)
|
|
|
|
|
2020-02-13 20:38:23 +03:00
|
|
|
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)
|
|
|
|
|
2022-04-19 20:48:53 +03:00
|
|
|
@pytest.mark.parametrize("transport", ['http', 'websocket'])
|
|
|
|
@pytest.mark.usefixtures(
|
|
|
|
"graphql_service",
|
|
|
|
"actions_fixture",
|
|
|
|
'per_class_tests_db_state'
|
|
|
|
)
|
|
|
|
class TestActionsRelationshipsBasic:
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/relationships/basic'
|
|
|
|
|
|
|
|
def test_query_with_relationships(self, hge_ctx, transport):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/query_with_relationships.yaml', transport)
|
|
|
|
|
2020-03-20 09:46:45 +03:00
|
|
|
@use_action_fixtures
|
|
|
|
class TestActionsSync:
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/sync'
|
|
|
|
|
2021-10-11 09:55:05 +03:00
|
|
|
def test_null_response(self, hge_ctx):
|
|
|
|
check_query_secret(hge_ctx, self.dir() + '/null_response.yaml')
|
2023-02-07 18:32:38 +03:00
|
|
|
|
|
|
|
def test_omitted_field_response_for_nullable_field(self, hge_ctx):
|
|
|
|
check_query_secret(hge_ctx, self.dir() + '/omitted_field_response_for_nullable_field.yaml')
|
2021-12-16 02:51:52 +03:00
|
|
|
|
2021-10-11 09:55:05 +03:00
|
|
|
def test_expecting_object_response_got_null(self, hge_ctx):
|
|
|
|
check_query_secret(hge_ctx, self.dir() + '/expecting_object_response_got_null.yaml')
|
|
|
|
|
|
|
|
def test_expecting_array_response_got_null(self, hge_ctx):
|
|
|
|
check_query_secret(hge_ctx, self.dir() + '/expecting_array_response_got_null.yaml')
|
|
|
|
|
|
|
|
def test_expecting_object_response_got_array(self, hge_ctx):
|
2020-04-24 10:55:51 +03:00
|
|
|
check_query_secret(hge_ctx, self.dir() + '/expecting_object_response.yaml')
|
2020-02-13 20:38:23 +03:00
|
|
|
|
2021-10-11 09:55:05 +03:00
|
|
|
def test_expecting_array_response_got_object(self, hge_ctx):
|
2020-04-24 10:55:51 +03:00
|
|
|
check_query_secret(hge_ctx, self.dir() + '/expecting_array_response.yaml')
|
2022-08-15 17:57:55 +03:00
|
|
|
|
|
|
|
# Scalar webhook response tests.
|
2022-02-15 17:39:35 +03:00
|
|
|
def test_expecting_scalar_output_type_success(self, hge_ctx):
|
|
|
|
check_query_secret(hge_ctx, self.dir() + '/get_scalar_action_output_type_success.yaml')
|
2022-03-03 06:43:27 +03:00
|
|
|
|
2022-02-15 17:39:35 +03:00
|
|
|
def test_expecting_scalar_string_output_type_got_object(self, hge_ctx):
|
|
|
|
check_query_secret(hge_ctx, self.dir() + '/expecting_scalar_response_got_object.yaml')
|
2022-06-03 12:47:10 +03:00
|
|
|
|
2022-05-31 08:22:46 +03:00
|
|
|
def test_expecting_object_output_type_got_scalar_string(self, hge_ctx):
|
2022-02-15 17:39:35 +03:00
|
|
|
check_query_secret(hge_ctx, self.dir() + '/expecting_object_response_got_scalar.yaml')
|
2022-03-03 06:43:27 +03:00
|
|
|
|
2022-02-15 17:39:35 +03:00
|
|
|
def test_scalar_response_action_transformed_output(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/scalar_response_action_transformed_output.yaml')
|
2022-03-03 06:43:27 +03:00
|
|
|
|
2022-02-15 17:39:35 +03:00
|
|
|
def test_object_response_action_transformed_output(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/object_response_action_transformed_output.yaml')
|
2022-08-15 17:57:55 +03:00
|
|
|
|
2022-05-31 08:22:46 +03:00
|
|
|
# Scalar array tests
|
|
|
|
def test_expecting_string_scalar_array_output_type_success(self, hge_ctx):
|
|
|
|
check_query_secret(hge_ctx, self.dir() + '/get_string_scalar_array_action_output_type_success.yaml')
|
2022-08-15 17:57:55 +03:00
|
|
|
|
2022-05-31 08:22:46 +03:00
|
|
|
def test_expecting_number_scalar_array_output_type_got_string_array(self, hge_ctx):
|
|
|
|
check_query_secret(hge_ctx, self.dir() + '/get_string_scalar_array_action_output_type_expecting_number_array.yaml')
|
2022-08-15 17:57:55 +03:00
|
|
|
|
2022-05-31 08:22:46 +03:00
|
|
|
def test_scalar_array_field_nullability_check(self, hge_ctx):
|
|
|
|
check_query_secret(hge_ctx, self.dir() + '/get_null_field_expecting_non_nullable_field_array.yaml')
|
2021-12-16 02:51:52 +03:00
|
|
|
|
2022-04-18 12:58:15 +03:00
|
|
|
def test_expecting_object_response_with_nested_null(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/expecting_object_response_with_nested_null.yaml')
|
2022-08-15 17:57:55 +03:00
|
|
|
|
2022-06-03 12:47:10 +03:00
|
|
|
def test_expecting_jsonb_response_success(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/expecting_jsonb_response_success.yaml')
|
2022-08-15 17:57:55 +03:00
|
|
|
|
2022-06-03 12:47:10 +03:00
|
|
|
def test_expecting_custom_scalar_response_success(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/expecting_custom_scalar_response_success.yaml')
|
2022-08-15 17:57:55 +03:00
|
|
|
|
2022-06-03 12:47:10 +03:00
|
|
|
def test_expecting_custom_scalar_array_response_success(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/expecting_custom_scalar_array_response_success.yaml')
|
2022-08-15 17:57:55 +03:00
|
|
|
|
2022-06-03 12:47:10 +03:00
|
|
|
def test_expecting_custom_scalar_array_response_got_different_type(self, hge_ctx):
|
|
|
|
query_obj = {
|
|
|
|
"query": """
|
|
|
|
mutation {
|
|
|
|
custom_scalar_nested_array_response
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
}
|
|
|
|
headers = {}
|
|
|
|
admin_secret = hge_ctx.hge_key
|
|
|
|
if admin_secret is not None:
|
|
|
|
headers['X-Hasura-Admin-Secret'] = admin_secret
|
|
|
|
code, resp, _ = hge_ctx.anyq('/v1/graphql', query_obj, headers)
|
|
|
|
assert code == 200, resp
|
|
|
|
|
|
|
|
error_message = resp['errors'][0]['message']
|
|
|
|
|
|
|
|
assert error_message == 'expecting array for the action webhook response', error_message
|
2022-04-18 12:58:15 +03:00
|
|
|
|
|
|
|
def test_expecting_object_response_with_nested_null_wrong_field(self, hge_ctx):
|
|
|
|
query_obj = {
|
|
|
|
"query": """
|
|
|
|
query {
|
|
|
|
typed_nested_null_wrong_field {
|
|
|
|
id
|
|
|
|
child {
|
|
|
|
id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
}
|
|
|
|
headers = {}
|
|
|
|
admin_secret = hge_ctx.hge_key
|
|
|
|
if admin_secret is not None:
|
|
|
|
headers['X-Hasura-Admin-Secret'] = admin_secret
|
|
|
|
code, resp, _ = hge_ctx.anyq('/v1/graphql', query_obj, headers)
|
|
|
|
assert code == 200, resp
|
|
|
|
|
|
|
|
error_message = resp['errors'][0]['message']
|
|
|
|
|
|
|
|
assert error_message == 'expecting not null value for field "id"', error_message
|
2020-02-13 20:38:23 +03:00
|
|
|
|
2020-03-20 09:46:45 +03:00
|
|
|
# Webhook response validation tests. See https://github.com/hasura/graphql-engine/issues/3977
|
|
|
|
def test_mirror_action_not_null(self, hge_ctx):
|
2020-04-24 10:55:51 +03:00
|
|
|
check_query_secret(hge_ctx, self.dir() + '/mirror_action_not_null.yaml')
|
2020-03-20 09:46:45 +03:00
|
|
|
|
|
|
|
def test_mirror_action_unexpected_field(self, hge_ctx):
|
2020-04-24 10:55:51 +03:00
|
|
|
check_query_secret(hge_ctx, self.dir() + '/mirror_action_unexpected_field.yaml')
|
2020-03-20 09:46:45 +03:00
|
|
|
|
|
|
|
def test_mirror_action_no_field(self, hge_ctx):
|
2020-04-24 10:55:51 +03:00
|
|
|
check_query_secret(hge_ctx, self.dir() + '/mirror_action_no_field.yaml')
|
2020-03-20 09:46:45 +03:00
|
|
|
|
|
|
|
def test_mirror_action_success(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/mirror_action_success.yaml')
|
|
|
|
|
2021-09-16 14:03:01 +03:00
|
|
|
def test_mirror_action_transformed_success(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/mirror_action_transformed_success.yaml')
|
|
|
|
|
2022-01-19 07:46:42 +03:00
|
|
|
def test_mirror_action_transformed_output_success(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/mirror_action_transformed_output_success.yaml')
|
|
|
|
|
2022-01-31 09:49:11 +03:00
|
|
|
def test_mirror_headers(self, hge_ctx):
|
|
|
|
query = """
|
|
|
|
query {
|
|
|
|
mirror_headers {
|
|
|
|
headers {
|
|
|
|
name
|
|
|
|
value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
query_obj = {
|
|
|
|
"query": query
|
|
|
|
}
|
|
|
|
headers = {}
|
|
|
|
admin_secret = hge_ctx.hge_key
|
|
|
|
if admin_secret is not None:
|
|
|
|
headers['X-Hasura-Admin-Secret'] = admin_secret
|
|
|
|
code, resp, _ = hge_ctx.anyq('/v1/graphql', query_obj, headers)
|
|
|
|
assert code == 200, resp
|
|
|
|
|
|
|
|
resp_headers = resp['data']['mirror_headers']['headers']
|
|
|
|
|
|
|
|
user_agent_header = next((h['value'] for h in resp_headers if h['name'] == 'User-Agent'), None)
|
|
|
|
assert user_agent_header is not None
|
|
|
|
assert user_agent_header.startswith("hasura-graphql-engine/")
|
|
|
|
|
2022-01-19 07:46:42 +03:00
|
|
|
def test_results_list_transformed_output_success(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/results_list_transformed_output_success.yaml')
|
|
|
|
|
2021-03-22 13:56:44 +03:00
|
|
|
#https://github.com/hasura/graphql-engine/issues/6631
|
|
|
|
def test_create_users_output_type(self, hge_ctx):
|
|
|
|
gql_query = '''
|
|
|
|
query {
|
|
|
|
__type(name: "mutation_root"){
|
|
|
|
fields {
|
|
|
|
name
|
|
|
|
type{
|
|
|
|
kind
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': gql_query
|
|
|
|
}
|
|
|
|
headers = {}
|
|
|
|
admin_secret = hge_ctx.hge_key
|
|
|
|
if admin_secret is not None:
|
|
|
|
headers['X-Hasura-Admin-Secret'] = admin_secret
|
|
|
|
code, resp, _ = hge_ctx.anyq('/v1/graphql', query, headers)
|
|
|
|
assert code == 200, resp
|
|
|
|
resp_data = resp['data']
|
|
|
|
mutation_root_fields = resp_data['__type']['fields']
|
|
|
|
# check type for create_users root field
|
|
|
|
for root_field in mutation_root_fields:
|
|
|
|
if root_field['name'] == 'create_users':
|
|
|
|
assert root_field['type']['kind'] == 'LIST', root_field
|
|
|
|
|
2020-06-05 15:03:18 +03:00
|
|
|
@use_action_fixtures_with_remote_joins
|
|
|
|
class TestActionsSyncWithRemoteJoins:
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/sync/remote_joins'
|
|
|
|
|
|
|
|
def test_action_with_remote_joins(self,hge_ctx):
|
|
|
|
check_query_f(hge_ctx,self.dir() + '/action_with_remote_joins.yaml')
|
|
|
|
|
2020-04-24 10:55:51 +03:00
|
|
|
# Check query with admin secret tokens
|
|
|
|
def check_query_secret(hge_ctx, f):
|
|
|
|
conf = get_conf_f(f)
|
|
|
|
admin_secret = hge_ctx.hge_key
|
|
|
|
def add_secret(c):
|
|
|
|
if admin_secret is not None:
|
|
|
|
if 'headers' in c:
|
|
|
|
c['headers']['x-hasura-admin-secret'] = admin_secret
|
|
|
|
else:
|
|
|
|
c['headers'] = {
|
|
|
|
'x-hasura-admin-secret': admin_secret
|
|
|
|
}
|
|
|
|
return c
|
|
|
|
|
|
|
|
if isinstance(conf, list):
|
|
|
|
for _, sconf in enumerate(conf):
|
|
|
|
check_query(hge_ctx, add_secret(sconf), add_auth = False)
|
|
|
|
else:
|
|
|
|
check_query(hge_ctx, add_secret(conf), add_auth = False)
|
|
|
|
|
2020-04-16 10:25:19 +03:00
|
|
|
@use_action_fixtures
|
|
|
|
class TestQueryActions:
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/sync'
|
|
|
|
|
2021-09-17 10:43:43 +03:00
|
|
|
# toplevel, extensions with error
|
|
|
|
def test_query_action_extensions_code_both_codes_fail(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/extensions_code_both_codes.yaml')
|
|
|
|
# toplevel, extensions with no error
|
|
|
|
def test_query_action_extensions_code_toplevel_empty_extensions_fail(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/extensions_code_toplevel_empty_extensions.yaml')
|
|
|
|
# toplevel, no extensions
|
|
|
|
def test_query_action_extensions_code_toplevel_no_extensions_fail(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/extensions_code_toplevel_no_extensions.yaml')
|
|
|
|
# no toplevel, extensions with error
|
|
|
|
def test_query_action_extensions_code_only_extensions_code_fail(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/extensions_code_only_extensions_code.yaml')
|
|
|
|
# no toplevel, extensions with no error
|
|
|
|
def test_query_action_extensions_code_only_empty_extensions_fail(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/extensions_code_only_empty_extensions.yaml')
|
|
|
|
# no toplevel, no extensions
|
|
|
|
def test_query_action_extensions_code_nothing_fail(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/extensions_code_nothing.yaml')
|
|
|
|
|
2020-04-16 10:25:19 +03:00
|
|
|
def test_query_action_fail(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/get_user_by_email_fail.yaml')
|
|
|
|
|
|
|
|
def test_query_action_success_output_object(self, hge_ctx):
|
|
|
|
gql_query = '''
|
|
|
|
mutation {
|
|
|
|
insert_user_one(object: {email: "clarke@gmail.com", name:"Clarke"}){
|
|
|
|
id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': gql_query
|
|
|
|
}
|
|
|
|
headers = {}
|
|
|
|
admin_secret = hge_ctx.hge_key
|
|
|
|
if admin_secret is not None:
|
|
|
|
headers['X-Hasura-Admin-Secret'] = admin_secret
|
|
|
|
code, resp, _ = hge_ctx.anyq('/v1/graphql', query, headers)
|
|
|
|
assert code == 200,resp
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/get_user_by_email_success.yaml')
|
|
|
|
|
2021-12-16 02:51:52 +03:00
|
|
|
def test_query_action_success_output_nested_object(self, hge_ctx):
|
|
|
|
gql_query = '''
|
|
|
|
mutation {
|
|
|
|
insert_user_one(object: {email: "clarke@gmail.com", name:"Clarke"}){
|
|
|
|
id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': gql_query
|
|
|
|
}
|
|
|
|
headers = {}
|
|
|
|
admin_secret = hge_ctx.hge_key
|
|
|
|
if admin_secret is not None:
|
|
|
|
headers['X-Hasura-Admin-Secret'] = admin_secret
|
|
|
|
code, resp, _ = hge_ctx.anyq('/v1/graphql', query, headers)
|
|
|
|
assert code == 200,resp
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/get_user_by_email_nested_success.yaml')
|
|
|
|
|
2022-03-03 06:43:27 +03:00
|
|
|
def test_query_action_success_output_nested_join(self, hge_ctx):
|
|
|
|
gql_query = '''
|
|
|
|
mutation {
|
|
|
|
insert_user_one(object: {email: "clarke@gmail.com", name:"Clarke"}){
|
|
|
|
id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': gql_query
|
|
|
|
}
|
|
|
|
headers = {}
|
|
|
|
admin_secret = hge_ctx.hge_key
|
|
|
|
if admin_secret is not None:
|
|
|
|
headers['X-Hasura-Admin-Secret'] = admin_secret
|
|
|
|
code, resp, _ = hge_ctx.anyq('/v1/graphql', query, headers)
|
|
|
|
assert code == 200,resp
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/get_user_by_email_nested_join_success.yaml')
|
|
|
|
|
2020-04-16 10:25:19 +03:00
|
|
|
def test_query_action_success_output_list(self, hge_ctx):
|
|
|
|
gql_query = '''
|
|
|
|
mutation {
|
|
|
|
insert_user(objects:
|
|
|
|
[{id:1,email: "clarke@gmail.com", name:"Clarke 1"},
|
|
|
|
{id:2,email: "clarke@gmail.com", name:"Clarke 2"}])
|
|
|
|
{
|
|
|
|
returning {
|
|
|
|
id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': gql_query
|
|
|
|
}
|
|
|
|
headers = {}
|
|
|
|
admin_secret = hge_ctx.hge_key
|
|
|
|
if admin_secret is not None:
|
|
|
|
headers['X-Hasura-Admin-Secret'] = admin_secret
|
|
|
|
code, resp, _ = hge_ctx.anyq('/v1/graphql', query, headers)
|
|
|
|
assert code == 200,resp
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/get_users_by_email_success.yaml')
|
|
|
|
|
2020-04-24 09:09:00 +03:00
|
|
|
# This test is to make sure that query actions work well with variables.
|
|
|
|
# Earlier the HGE used to add the query action to the plan cache, which
|
|
|
|
# results in interrmittent validation errors, like:
|
|
|
|
# {
|
|
|
|
# "errors": [
|
|
|
|
# {
|
|
|
|
# "extensions": {
|
|
|
|
# "path": "$.variableValues",
|
|
|
|
# "code": "validation-failed"
|
|
|
|
# },
|
|
|
|
# "message": "unexpected variables: email"
|
|
|
|
# }
|
|
|
|
# ]
|
|
|
|
# }
|
|
|
|
def test_query_action_should_not_throw_validation_error(self, hge_ctx):
|
|
|
|
for _ in range(25):
|
|
|
|
self.test_query_action_success_output_object(hge_ctx)
|
2020-04-16 10:25:19 +03:00
|
|
|
|
2021-01-12 15:03:21 +03:00
|
|
|
def test_query_action_with_relationship(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/query_action_relationship_with_permission.yaml')
|
|
|
|
|
2021-12-16 02:51:52 +03:00
|
|
|
def test_query_action_recursive_output(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/query_action_recursive_output.yaml')
|
|
|
|
|
2020-03-20 09:46:45 +03:00
|
|
|
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
|
|
|
|
|
2020-02-13 20:38:23 +03:00
|
|
|
@use_action_fixtures
|
2020-03-20 09:46:45 +03:00
|
|
|
class TestActionsSyncResponseHeaders:
|
|
|
|
|
2020-02-13 20:38:23 +03:00
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
2020-03-20 09:46:45 +03:00
|
|
|
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
|
2020-02-13 20:38:23 +03:00
|
|
|
|
|
|
|
|
2020-03-20 09:46:45 +03:00
|
|
|
@use_action_fixtures
|
|
|
|
class TestActionsAsync:
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/async'
|
2020-02-13 20:38:23 +03:00
|
|
|
|
|
|
|
def test_create_user_fail(self, hge_ctx):
|
|
|
|
graphql_mutation = '''
|
|
|
|
mutation {
|
|
|
|
create_user(email: "random-email", name: "Clarke")
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': graphql_mutation,
|
|
|
|
'variables': {}
|
|
|
|
}
|
2020-03-20 09:46:45 +03:00
|
|
|
status, resp, _ = hge_ctx.anyq('/v1/graphql', query, mk_headers_with_secret(hge_ctx))
|
2020-02-13 20:38:23 +03:00
|
|
|
assert status == 200, resp
|
|
|
|
assert 'data' in resp
|
|
|
|
action_id = resp['data']['create_user']
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2020-04-21 13:25:56 +03:00
|
|
|
check_query_timeout(hge_ctx, conf, True, 10)
|
2023-12-18 13:30:27 +03:00
|
|
|
|
|
|
|
def test_async_actions_error_response_user_role(self, hge_ctx):
|
|
|
|
graphql_mutation = '''
|
|
|
|
mutation {
|
|
|
|
test_async_action_error_response
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': graphql_mutation,
|
|
|
|
'variables': {}
|
|
|
|
}
|
|
|
|
status, resp, _ = hge_ctx.anyq('/v1/graphql', query, mk_headers_with_secret(hge_ctx, {'x-hasura-role': 'user'}))
|
|
|
|
assert status == 200, resp
|
|
|
|
assert 'data' in resp
|
|
|
|
action_id = resp['data']['test_async_action_error_response']
|
|
|
|
query_async = '''
|
|
|
|
query ($action_id: uuid!){
|
|
|
|
test_async_action_error_response(id: $action_id){
|
|
|
|
id
|
|
|
|
errors
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': query_async,
|
|
|
|
'variables': {
|
|
|
|
'action_id': action_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
response = {
|
|
|
|
'data': {
|
|
|
|
'test_async_action_error_response': {
|
|
|
|
'id': action_id,
|
|
|
|
'errors': {
|
|
|
|
'code': 'unexpected',
|
|
|
|
'path': '$',
|
|
|
|
'error': 'not a valid json response from webhook'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
conf = {
|
|
|
|
'url': '/v1/graphql',
|
|
|
|
'headers': {
|
|
|
|
'x-hasura-role': 'user',
|
|
|
|
},
|
|
|
|
'query': query,
|
|
|
|
'status': 200,
|
|
|
|
'response': response
|
|
|
|
}
|
|
|
|
check_query_timeout(hge_ctx, conf, True, 10)
|
|
|
|
|
|
|
|
def test_async_actions_error_response_admin_role(self, hge_ctx):
|
|
|
|
graphql_mutation = '''
|
|
|
|
mutation {
|
|
|
|
test_async_action_error_response
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': graphql_mutation,
|
|
|
|
'variables': {}
|
|
|
|
}
|
|
|
|
status, resp, _ = hge_ctx.anyq('/v1/graphql', query, mk_headers_with_secret(hge_ctx, {'x-hasura-role': 'admin'}))
|
|
|
|
assert status == 200, resp
|
|
|
|
assert 'data' in resp
|
|
|
|
action_id = resp['data']['test_async_action_error_response']
|
|
|
|
query_async = '''
|
|
|
|
query ($action_id: uuid!){
|
|
|
|
test_async_action_error_response(id: $action_id){
|
|
|
|
id
|
|
|
|
errors
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': query_async,
|
|
|
|
'variables': {
|
|
|
|
'action_id': action_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
conf = {
|
|
|
|
'url': '/v1/graphql',
|
|
|
|
'headers': {
|
|
|
|
'x-hasura-role': 'admin',
|
|
|
|
},
|
|
|
|
'query': query,
|
|
|
|
'status': 200,
|
|
|
|
}
|
|
|
|
time.sleep(10)
|
|
|
|
response, _ = check_query(hge_ctx, conf)
|
2020-02-13 20:38:23 +03:00
|
|
|
|
2023-12-18 13:30:27 +03:00
|
|
|
assert 'errors' in response['data']['test_async_action_error_response']
|
|
|
|
assert 'internal' in response['data']['test_async_action_error_response']['errors']
|
|
|
|
|
2020-02-13 20:38:23 +03:00
|
|
|
def test_create_user_success(self, hge_ctx):
|
|
|
|
graphql_mutation = '''
|
|
|
|
mutation {
|
|
|
|
create_user(email: "clarke@hasura.io", name: "Clarke")
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': graphql_mutation,
|
|
|
|
'variables': {}
|
|
|
|
}
|
2020-03-20 09:46:45 +03:00
|
|
|
status, resp, _ = hge_ctx.anyq('/v1/graphql', query, mk_headers_with_secret(hge_ctx))
|
2020-02-13 20:38:23 +03:00
|
|
|
assert status == 200, resp
|
|
|
|
assert 'data' in resp
|
|
|
|
action_id = resp['data']['create_user']
|
|
|
|
|
|
|
|
query_async = '''
|
|
|
|
query ($action_id: uuid!){
|
|
|
|
create_user(id: $action_id){
|
2020-03-11 14:39:00 +03:00
|
|
|
__typename
|
2020-02-13 20:38:23 +03:00
|
|
|
id
|
|
|
|
output {
|
2020-03-11 14:39:00 +03:00
|
|
|
__typename
|
2020-02-13 20:38:23 +03:00
|
|
|
id
|
|
|
|
user {
|
2020-03-11 14:39:00 +03:00
|
|
|
__typename
|
2020-02-13 20:38:23 +03:00
|
|
|
name
|
|
|
|
email
|
|
|
|
is_admin
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': query_async,
|
|
|
|
'variables': {
|
|
|
|
'action_id': action_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
response = {
|
|
|
|
'data': {
|
|
|
|
'create_user': {
|
2020-03-11 14:39:00 +03:00
|
|
|
'__typename': 'create_user',
|
2020-02-13 20:38:23 +03:00
|
|
|
'id': action_id,
|
|
|
|
'output': {
|
2020-03-11 14:39:00 +03:00
|
|
|
'__typename': 'UserId',
|
2020-02-13 20:38:23 +03:00
|
|
|
'id': 1,
|
|
|
|
'user': {
|
2020-03-11 14:39:00 +03:00
|
|
|
'__typename': 'user',
|
2020-02-13 20:38:23 +03:00
|
|
|
'name': 'Clarke',
|
|
|
|
'email': 'clarke@hasura.io',
|
|
|
|
'is_admin': False
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
conf = {
|
|
|
|
'url': '/v1/graphql',
|
|
|
|
'headers': {},
|
|
|
|
'query': query,
|
|
|
|
'status': 200,
|
|
|
|
'response': response
|
|
|
|
}
|
2020-04-21 13:25:56 +03:00
|
|
|
check_query_timeout(hge_ctx, conf, True, 10)
|
2020-02-13 20:38:23 +03:00
|
|
|
|
|
|
|
def test_create_user_roles(self, hge_ctx):
|
|
|
|
graphql_mutation = '''
|
|
|
|
mutation {
|
|
|
|
create_user(email: "blake@hasura.io", name: "Blake")
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': graphql_mutation,
|
|
|
|
'variables': {}
|
|
|
|
}
|
2020-03-20 09:46:45 +03:00
|
|
|
headers_user_1 = mk_headers_with_secret(hge_ctx, {
|
2020-02-13 20:38:23 +03:00
|
|
|
'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']
|
|
|
|
|
|
|
|
query_async = '''
|
|
|
|
query ($action_id: uuid!){
|
|
|
|
create_user(id: $action_id){
|
|
|
|
id
|
|
|
|
output {
|
|
|
|
id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': query_async,
|
|
|
|
'variables': {
|
|
|
|
'action_id': action_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-20 09:46:45 +03:00
|
|
|
headers_user_2 = mk_headers_with_secret(hge_ctx, {
|
2020-02-13 20:38:23 +03:00
|
|
|
'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
|
2020-04-21 13:25:56 +03:00
|
|
|
check_query_timeout(hge_ctx, conf_user_2, add_auth = False, timeout = 10)
|
2020-02-13 20:38:23 +03:00
|
|
|
|
|
|
|
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
|
2020-04-21 13:25:56 +03:00
|
|
|
check_query_timeout(hge_ctx, conf_user_1, add_auth = False, timeout = 10)
|
|
|
|
|
2021-09-16 14:03:01 +03:00
|
|
|
def test_create_user_transformed_success(self, hge_ctx):
|
|
|
|
graphql_mutation = '''
|
|
|
|
mutation {
|
|
|
|
create_user_transformed(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_transformed']
|
|
|
|
|
|
|
|
query_async = '''
|
|
|
|
query ($action_id: uuid!){
|
|
|
|
create_user_transformed(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_transformed': {
|
|
|
|
'__typename': 'create_user_transformed',
|
|
|
|
'id': action_id,
|
|
|
|
'output': {
|
|
|
|
'__typename': 'UserId',
|
|
|
|
'id': 1,
|
|
|
|
'user': {
|
|
|
|
'__typename': 'user',
|
|
|
|
'name': 'notClarke',
|
|
|
|
'email': 'foo@bar.com',
|
|
|
|
'is_admin': False
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
conf = {
|
|
|
|
'url': '/v1/graphql',
|
|
|
|
'headers': {},
|
|
|
|
'query': query,
|
|
|
|
'status': 200,
|
|
|
|
'response': response
|
|
|
|
}
|
|
|
|
check_query_timeout(hge_ctx, conf, True, 10)
|
|
|
|
|
2021-12-16 02:51:52 +03:00
|
|
|
def test_create_user_nested_success(self, hge_ctx):
|
|
|
|
graphql_mutation = '''
|
|
|
|
mutation {
|
|
|
|
create_user_nested(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_nested']
|
|
|
|
|
|
|
|
query_async = '''
|
|
|
|
query ($action_id: uuid!){
|
|
|
|
create_user_nested(id: $action_id){
|
|
|
|
__typename
|
|
|
|
id
|
|
|
|
output {
|
|
|
|
__typename
|
|
|
|
userObj {
|
|
|
|
__typename
|
|
|
|
id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': query_async,
|
|
|
|
'variables': {
|
|
|
|
'action_id': action_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
response = {
|
|
|
|
'data': {
|
|
|
|
'create_user_nested': {
|
|
|
|
'__typename': 'create_user_nested',
|
|
|
|
'id': action_id,
|
|
|
|
'output': {
|
|
|
|
'__typename': 'UserIdNested',
|
|
|
|
'userObj': {
|
|
|
|
'__typename': 'UserIdObj',
|
|
|
|
'id': 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
conf = {
|
|
|
|
'url': '/v1/graphql',
|
|
|
|
'headers': {},
|
|
|
|
'query': query,
|
|
|
|
'status': 200,
|
|
|
|
'response': response
|
|
|
|
}
|
|
|
|
check_query_timeout(hge_ctx, conf, True, 10)
|
2021-09-16 14:03:01 +03:00
|
|
|
|
2020-04-21 13:25:56 +03:00
|
|
|
def check_query_timeout(hge_ctx, conf, add_auth, timeout):
|
|
|
|
wait_until = time.time() + timeout
|
|
|
|
while True:
|
|
|
|
time.sleep(2)
|
|
|
|
try:
|
|
|
|
check_query(hge_ctx, conf, add_auth = add_auth)
|
|
|
|
except AssertionError:
|
|
|
|
if time.time() > wait_until:
|
|
|
|
raise
|
|
|
|
else:
|
|
|
|
continue
|
|
|
|
break
|
2020-04-15 15:03:13 +03:00
|
|
|
|
2021-12-16 02:51:52 +03:00
|
|
|
@use_action_fixtures
|
|
|
|
class TestCreateActionNestedTypeWithRelation:
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/nested-relation'
|
2022-01-19 07:46:42 +03:00
|
|
|
|
2021-12-16 02:51:52 +03:00
|
|
|
# no toplevel, extensions with no error
|
|
|
|
def test_create_async_action_with_nested_output_and_relation_fail(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/create_async_action_with_nested_output_and_relation.yaml')
|
2022-01-19 07:46:42 +03:00
|
|
|
|
2021-12-16 02:51:52 +03:00
|
|
|
# no toplevel, extensions with no error
|
2022-03-03 06:43:27 +03:00
|
|
|
def test_create_sync_action_with_nested_output_and_nested_relation(self, hge_ctx):
|
2021-12-16 02:51:52 +03:00
|
|
|
check_query_f(hge_ctx, self.dir() + '/create_sync_action_with_nested_output_and_nested_relation.yaml')
|
|
|
|
|
2022-09-28 12:19:47 +03:00
|
|
|
@pytest.mark.usefixtures('postgis', 'actions_fixture', 'per_class_tests_db_state')
|
2020-04-15 15:03:13 +03:00
|
|
|
class TestSetCustomTypes:
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/custom-types'
|
|
|
|
|
2020-04-24 08:28:42 +03:00
|
|
|
def test_reuse_pgscalars(self, hge_ctx):
|
2020-04-15 15:03:13 +03:00
|
|
|
check_query_f(hge_ctx, self.dir() + '/reuse_pgscalars.yaml')
|
|
|
|
|
2020-04-24 08:28:42 +03:00
|
|
|
def test_reuse_unknown_pgscalar(self, hge_ctx):
|
2020-04-15 15:03:13 +03:00
|
|
|
check_query_f(hge_ctx, self.dir() + '/reuse_unknown_pgscalar.yaml')
|
|
|
|
|
|
|
|
def test_create_action_pg_scalar(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/create_action_pg_scalar.yaml')
|
2020-04-22 08:59:14 +03:00
|
|
|
|
2020-04-24 08:28:42 +03:00
|
|
|
def test_list_type_relationship(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/list_type_relationship.yaml')
|
|
|
|
|
2020-12-24 13:11:05 +03:00
|
|
|
def test_drop_relationship(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/drop_relationship.yaml')
|
|
|
|
|
2022-09-28 12:19:47 +03:00
|
|
|
@pytest.mark.usefixtures('actions_fixture', 'per_class_tests_db_state')
|
2020-04-22 08:59:14 +03:00
|
|
|
class TestActionsMetadata:
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/metadata'
|
|
|
|
|
|
|
|
def test_recreate_permission(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/recreate_permission.yaml')
|
2020-06-23 13:05:54 +03:00
|
|
|
|
2020-08-05 16:14:53 +03:00
|
|
|
def test_create_with_headers(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/create_with_headers.yaml')
|
|
|
|
|
2020-06-23 13:05:54 +03:00
|
|
|
@pytest.mark.usefixtures('per_class_tests_db_state')
|
|
|
|
class TestActionIntrospection:
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/introspection'
|
|
|
|
|
|
|
|
def test_introspection_query(self, hge_ctx):
|
|
|
|
conf = get_conf_f(self.dir() + '/introspection_query.yaml')
|
|
|
|
headers = {}
|
|
|
|
admin_secret = hge_ctx.hge_key
|
|
|
|
if admin_secret:
|
|
|
|
headers['X-Hasura-Admin-Secret'] = admin_secret
|
|
|
|
code, resp, _ = hge_ctx.anyq(conf['url'], conf['query'], headers)
|
|
|
|
assert code == 200, resp
|
|
|
|
assert 'data' in resp, resp
|
2020-09-16 12:53:17 +03:00
|
|
|
|
2021-05-18 11:47:55 +03:00
|
|
|
def test_output_types(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/output_types_query.yaml')
|
|
|
|
|
2021-08-11 15:41:34 +03:00
|
|
|
@pytest.mark.usefixtures('per_class_tests_db_state')
|
|
|
|
class TestFunctionReturnTypeIntrospection:
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/introspection/function_return_type'
|
|
|
|
|
|
|
|
def test_function_return_type(self, hge_ctx):
|
|
|
|
check_query_f(hge_ctx, self.dir() + '/function_return_type.yaml')
|
|
|
|
|
2021-05-18 11:47:55 +03:00
|
|
|
|
2020-09-16 12:53:17 +03:00
|
|
|
@use_action_fixtures
|
|
|
|
class TestActionTimeout:
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def dir(cls):
|
|
|
|
return 'queries/actions/timeout'
|
|
|
|
|
|
|
|
def test_action_timeout_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']
|
|
|
|
query_async = '''
|
|
|
|
query ($action_id: uuid!){
|
|
|
|
create_user(id: $action_id){
|
|
|
|
id
|
|
|
|
errors
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
query = {
|
|
|
|
'query': query_async,
|
|
|
|
'variables': {
|
|
|
|
'action_id': action_id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
conf = {
|
|
|
|
'url': '/v1/graphql',
|
|
|
|
'headers': {},
|
|
|
|
'query': query,
|
|
|
|
'status': 200,
|
|
|
|
}
|
2020-11-12 12:25:48 +03:00
|
|
|
# Since, the above is an async action, we don't wait for the execution of the webhook.
|
|
|
|
# We need this sleep of 4 seconds here because only after 3 seconds (sleep duration in the handler)
|
|
|
|
# we will be getting the result, otherwise the following asserts will fail because the
|
|
|
|
# response will be empty. This 4 seconds sleep will be concurrent with the sleep duration
|
|
|
|
# of the handler's execution. So, total time taken for this test will be 4 seconds.
|
2020-09-16 12:53:17 +03:00
|
|
|
time.sleep(4)
|
|
|
|
response, _ = check_query(hge_ctx, conf)
|
2022-08-15 17:57:55 +03:00
|
|
|
|
2020-09-16 12:53:17 +03:00
|
|
|
assert 'errors' in response['data']['create_user']
|
2021-09-20 16:14:28 +03:00
|
|
|
assert 'Response timeout' == response['data']['create_user']['errors']['internal']['error']['message']
|
2022-08-15 17:57:55 +03:00
|
|
|
|
2022-05-23 14:12:45 +03:00
|
|
|
# tests that actions webhook url environment variable template did not serialize in the error message
|
|
|
|
assert "{{ACTION_WEBHOOK_HANDLER}}/create-user-timeout" == response['data']['create_user']['errors']['internal']['request']['url']
|