graphql-engine/server/tests-py/test_remote_relationships.py
Samir Talwar 8d7c089273 server/tests-py: Start some node.js test services on random ports.
Where possible, we start the services on random ports, to avoid
port conflicts when parallelizing tests in the future.

When this isn't possible, we explicitly state the port, and wait for the
service to start. This is typically because the GraphQL Engine has already
started with knowledge of the relevant service passed in through an
environment variable.

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/5542
GitOrigin-RevId: b51a095b8710e3ff20d1edb13aa576c5272a5565
2022-09-07 16:26:10 +00:00

352 lines
14 KiB
Python

#!/usr/bin/env python3
import pytest
import subprocess
import time
from validate import check_query_f, check_query
from remote_server import NodeGraphQL
@pytest.fixture(scope="module")
def graphql_service():
svc = NodeGraphQL(["node", "remote_schemas/nodejs/index.js"], port=4001)
svc.start()
yield svc
svc.stop()
use_test_fixtures = pytest.mark.usefixtures(
"graphql_service",
"per_method_tests_db_state"
)
@use_test_fixtures
class TestCreateRemoteRelationship:
@classmethod
def dir(cls):
return "queries/remote_schemas/remote_relationships/"
# @pytest.fixture(autouse=True)
# def transact(self, hge_ctx, graphql_service):
# print("In setup method")
# graphql_service.start()
# try:
# hge_ctx.v1q_f(self.dir() + 'setup.yaml')
# yield
# hge_ctx.v1q_f(self.dir() + 'teardown.yaml')
# finally:
# graphql_service.stop()
def test_create_valid(self, hge_ctx):
files = [
'setup_remote_rel_basic.yaml',
'setup_remote_rel_nested_args.yaml',
'setup_remote_rel_array.yaml',
'setup_remote_rel_nested_fields.yaml',
'setup_remote_rel_multiple_fields.yaml',
'setup_remote_rel_joining_singleton_with_array.yaml',
'setup_remote_rel_with_interface.yaml',
'setup_remote_rel_with_union.yaml',
'setup_remote_rel_with_enum.yaml',
'setup_remote_rel_computed_fields.yaml',
]
for f in files:
hge_ctx.v1q_f(self.dir() + f)
def test_create_invalid(self, hge_ctx):
files = [
'setup_invalid_remote_rel_hasura_field.yaml',
'setup_invalid_remote_rel_literal.yaml',
'setup_invalid_remote_rel_variable.yaml',
'setup_invalid_remote_rel_remote_args.yaml',
'setup_invalid_remote_rel_remote_schema.yaml',
'setup_invalid_remote_rel_remote_field.yaml',
'setup_invalid_remote_rel_nested_args.yaml',
'setup_invalid_remote_rel_array.yaml',
'setup_invalid_remote_rel_computed_field.yaml',
]
for f in files:
hge_ctx.v1q_f(self.dir() + f, expected_status_code = 400)
def test_generation(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_nested_args.yaml')
check_query_f(hge_ctx, self.dir() + 'select_remote_fields.yaml')
@use_test_fixtures
class TestDeleteRemoteRelationship:
@classmethod
def dir(cls):
return "queries/remote_schemas/remote_relationships/"
def test_delete(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
hge_ctx.v1q_f(self.dir() + 'delete_remote_rel.yaml')
def test_delete_dependencies(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
hge_ctx.v1q_f(self.dir() + 'remove_remote_schema.yaml', expected_status_code = 400)
hge_ctx.v1q_f(self.dir() + 'delete_remote_rel.yaml')
def test_deleting_column_with_remote_relationship_dependency(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + 'drop_col_with_remote_rel_dependency.yaml')
self._check_no_remote_relationships(hge_ctx, 'profiles')
def test_deleting_table_with_remote_relationship_dependency(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + 'drop_table_with_remote_rel_dependency.yaml')
self._check_no_remote_relationships(hge_ctx, 'profiles')
def _check_no_remote_relationships(self, hge_ctx, table):
export_metadata_q = {
'type': 'export_metadata',
'args': {}
}
resp = hge_ctx.v1q(export_metadata_q)
tables = resp['sources'][0]['tables']
for t in tables:
if t['table']['name'] == table:
assert 'event_triggers' not in t
@use_test_fixtures
class TestUpdateRemoteRelationship:
@classmethod
def dir(cls):
return "queries/remote_schemas/remote_relationships/"
def test_update(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_relationship.yaml')
hge_ctx.v1q_f(self.dir() + 'update_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'update_basic_query.yaml')
@use_test_fixtures
class TestExecution:
@classmethod
def dir(cls):
return "queries/remote_schemas/remote_relationships/"
# def test_basic_mixed(self, hge_ctx):
# check_query_f(hge_ctx, self.dir() + 'basic_mixed.yaml')
def test_basic_relationship(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_relationship.yaml')
def test_basic_relationship_on_object(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_object_rel.yaml')
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_nested_args.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_arr_rel.yaml')
def test_regression_7172(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_regression_7172.yaml')
check_query_f(hge_ctx, self.dir() + 'regression_7172.yaml')
def test_basic_relationship_joining_singleton_to_array(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_joining_singleton_with_array.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_relationship_joining_singleton_with_array.yaml')
def test_basic_array(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_array.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_array.yaml')
def test_basic_array_without_join_key(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_array.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_array_without_join_key.yaml')
def test_multiple_fields(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_multiple_fields.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_multiple_fields.yaml')
# https://github.com/hasura/graphql-engine/issues/5448
def test_remote_join_fields_with_null_joining_fields(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_null_joining_fields.yaml')
check_query_f(hge_ctx, self.dir() + 'remote_rel_with_null_joining_fields.yaml')
def test_nested_fields(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_nested_fields.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_nested_fields.yaml')
def test_arguments(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_nested_args.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_arguments.yaml')
def test_with_variables(self, hge_ctx):
# check_query_f(hge_ctx, self.dir() + 'mixed_variables.yaml') -- uses heterogenous execution, due to which this assert fails
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_nested_args.yaml')
check_query_f(hge_ctx, self.dir() + 'remote_rel_variables.yaml')
def test_with_fragments(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + 'mixed_fragments.yaml')
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'remote_rel_fragments.yaml')
def test_with_interface(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_with_interface.yaml')
check_query_f(hge_ctx, self.dir() + 'mixed_interface.yaml')
check_query_f(hge_ctx, self.dir() + 'remote_rel_interface.yaml')
def test_with_union(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_with_union.yaml')
check_query_f(hge_ctx, self.dir() + 'remote_rel_union.yaml')
def test_with_enum(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_with_enum.yaml')
check_query_f(hge_ctx, self.dir() + 'remote_rel_enum.yaml')
def test_with_errors(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_errors_obj.yaml')
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_nested_args.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_errors_arr.yaml')
def test_with_aliased_remote_join_keys(self, hge_ctx):
"""
Regression test for https://github.com/hasura/graphql-engine/issues/7180.
"""
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_relationship_alias.yaml')
def test_with_scalar_relationship(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_scalar.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_scalar_rel.yaml')
def test_renaming_column_with_remote_relationship_dependency(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_nested_args.yaml')
check_query_f(hge_ctx, self.dir() + 'rename_col_with_remote_rel_dependency.yaml')
def test_renaming_table_with_remote_relationship_dependency(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_nested_args.yaml')
check_query_f(hge_ctx, self.dir() + 'rename_table_with_remote_rel_dependency.yaml')
# The check for the presence of the remote relationships is deferred to later stage
# in the server source code. To run this test we need to use proper websocket client
# instead of HTTP.
# def test_remote_joins_with_subscription_should_throw_error(self, hge_ctx):
# hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
# check_query_f(hge_ctx, self.dir() + 'subscription_with_remote_join_fields.yaml')
def test_remote_joins_in_mutation_response(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic_with_authors.yaml')
check_query_f(hge_ctx, self.dir() + 'mutation_output_with_remote_join_fields.yaml')
class TestDeepExecution:
@classmethod
def dir(cls):
return "queries/remote_schemas/remote_relationships/"
@pytest.fixture(autouse=True)
def transact(self, hge_ctx, graphql_service):
print("In setup method")
hge_ctx.v1q_f(self.dir() + 'setup.yaml')
hge_ctx.v1q_f(self.dir() + 'setup_address.yaml')
yield
hge_ctx.v1q_f(self.dir() + 'teardown_address.yaml')
hge_ctx.v1q_f(self.dir() + 'teardown.yaml')
def test_with_deep_object(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_deep_nesting_obj.yaml')
def test_with_deep_array(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_nested_args.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_deep_nesting_arr.yaml')
def test_with_complex_path_object(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_deep_nesting_complex_path_obj.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_deep_nesting_complex_path_obj2.yaml')
def test_with_complex_path_array(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_deep_nesting_complex_path_arr.yaml')
check_query_f(hge_ctx, self.dir() + 'query_with_deep_nesting_complex_path_arr2.yaml')
class TestExecutionWithPermissions:
@classmethod
def dir(cls):
return "queries/remote_schemas/remote_relationships/"
@pytest.fixture(autouse=True)
def transact(self, hge_ctx, graphql_service):
print("In setup method")
hge_ctx.v1q_f(self.dir() + 'setup_with_permissions.yaml')
yield
hge_ctx.v1q_f(self.dir() + 'teardown.yaml')
def test_basic_relationship(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_relationship_with_permissions1.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_relationship_with_permissions2.yaml')
# Test queries that combine several remote relationships, nested in
# different ways, variously filtering different bits using permissions.
def test_complex_multiple_joins(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_multiple_remote_rel.yaml')
check_query_f(hge_ctx, self.dir() + 'complex_multiple_joins.yaml')
@use_test_fixtures
class TestWithRelay:
@classmethod
def dir(cls):
return "queries/remote_schemas/remote_relationships/"
def test_with_relay_fail(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + "with_relay.yaml")
@use_test_fixtures
class TestExecutionWithCustomization:
@classmethod
def dir(cls):
return "queries/remote_schemas/remote_relationships/schema_customization/"
def test_basic_relationship(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_basic.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_relationship.yaml')
def test_nested_fields(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_nested_fields.yaml')
check_query_f(hge_ctx, self.dir() + 'basic_nested_fields.yaml')
class TestComputedFieldsInRemoteRelationship:
@classmethod
def dir(cls):
return "queries/remote_schemas/remote_relationships/"
@pytest.fixture(autouse=True)
def transact(self, hge_ctx, graphql_service):
print("In setup method")
hge_ctx.v1q_f(self.dir() + 'setup.yaml')
hge_ctx.v1q_f(self.dir() + 'setup_remote_rel_computed_fields.yaml')
yield
hge_ctx.v1q_f(self.dir() + 'teardown.yaml')
def test_remote_join_with_computed_field(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + 'remote_join_with_computed_field.yaml')
def test_remote_join_with_computed_field_session(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + 'remote_join_with_computed_field_session.yaml')
@use_test_fixtures
class TestRemoteRelationshipFieldType:
@classmethod
def dir(cls):
return "queries/remote_schemas/remote_relationships"
def test_remote_relationship_field_type(self, hge_ctx):
hge_ctx.v1q_f(self.dir() + '/setup_remote_rel_nested_args.yaml')
check_query_f(hge_ctx, self.dir() + '/remote_relationship_field_type.yaml')