diff --git a/.circleci/test-server.sh b/.circleci/test-server.sh index 0d369e4b3fb27..bc9b97dda0380 100755 --- a/.circleci/test-server.sh +++ b/.circleci/test-server.sh @@ -74,7 +74,7 @@ init_hge_and_test_jwt() { run_hge_with_args serve wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-jwt-key-file="$key_file" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" \ + --hge-jwt-key-file="$key_file" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" \ "$@" kill_hge_servers } @@ -266,7 +266,7 @@ admin-secret) start_multiple_hge_servers - run_pytest_parallel --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" + run_pytest_parallel kill_hge_servers ;; @@ -282,7 +282,6 @@ admin-secret-unauthorized-role) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-unauthorized-role \ test_graphql_queries.py::TestUnauthorizedRolePermission @@ -302,7 +301,7 @@ jwt-rs512) start_multiple_hge_servers - run_pytest_parallel --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/jwt_private.key" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" + run_pytest_parallel --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/jwt_private.key" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" kill_hge_servers @@ -320,7 +319,7 @@ jwt-ed25519) start_multiple_hge_servers - run_pytest_parallel --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/ed25519_jwt_private.key" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" + run_pytest_parallel --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/ed25519_jwt_private.key" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" kill_hge_servers @@ -574,7 +573,7 @@ jwt-cookie-unauthorized-role) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/jwt_private.key" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" \ + --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/jwt_private.key" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" \ --test-unauthorized-role \ test_graphql_queries.py::TestFallbackUnauthorizedRoleCookie @@ -586,7 +585,7 @@ jwt-cookie-unauthorized-role) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/jwt_private.key" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" \ + --hge-jwt-key-file="$OUTPUT_FOLDER/ssl/jwt_private.key" --hge-jwt-conf="$HASURA_GRAPHQL_JWT_SECRET" \ --test-no-cookie-and-unauth-role \ test_graphql_queries.py::TestMissingUnauthorizedRoleAndCookie @@ -605,7 +604,6 @@ cors-domains) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_cors.py kill_hge_servers @@ -624,7 +622,7 @@ auth-webhook-cookie) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" \ + --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" \ --test-auth-webhook-header \ test_auth_webhook_cookie.py @@ -644,7 +642,6 @@ ws-init-cookie-read-cors-enabled) echo "$(time_elapsed): testcase 1: read cookie, cors enabled" pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-ws-init-cookie=read \ test_websocket_init_cookie.py @@ -662,7 +659,6 @@ ws-init-cookie-noread) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-ws-init-cookie=noread \ test_websocket_init_cookie.py @@ -680,7 +676,6 @@ ws-init-cookie-read-cors-disabled) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-ws-init-cookie=read \ test_websocket_init_cookie.py @@ -698,7 +693,6 @@ ws-graphql-api-disabled) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_apis_disabled.py kill_hge_servers @@ -716,7 +710,6 @@ ws-metadata-api-disabled) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_apis_disabled.py kill_hge_servers @@ -731,7 +724,6 @@ remote-schema-permissions) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_remote_schema_permissions.py unset HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS @@ -748,10 +740,8 @@ function-permissions) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_graphql_queries.py::TestGraphQLQueryFunctionPermissions pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_graphql_mutations.py::TestGraphQLMutationFunctions unset HASURA_GRAPHQL_INFER_FUNCTION_PERMISSIONS @@ -771,7 +761,6 @@ roles-inheritance) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_roles_inheritance.py unset HASURA_GRAPHQL_ADMIN_SECRET @@ -791,7 +780,6 @@ naming-conventions) unset HASURA_GRAPHQL_EXPERIMENTAL_FEATURES pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_naming_conventions.py kill_hge_servers @@ -801,7 +789,6 @@ naming-conventions) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_naming_conventions.py kill_hge_servers @@ -815,7 +802,6 @@ naming-conventions) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_naming_conventions.py unset HASURA_GRAPHQL_ADMIN_SECRET @@ -835,8 +821,6 @@ streaming-subscriptions) # run all the subscriptions tests with streaming subscriptions enabled pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ - --test-streaming-subscriptions \ test_subscriptions.py unset HASURA_GRAPHQL_ADMIN_SECRET @@ -853,7 +837,6 @@ query-caching) run_hge_with_args +RTS -N1 -RTS serve wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_graphql_queries.py::TestGraphQLQueryCaching kill_hge_servers ;; @@ -877,7 +860,6 @@ query-logs) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-logging \ test_logging.py @@ -912,7 +894,6 @@ startup-db-calls) run_hge_with_args serve wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-startup-db-calls \ test_startup_db_calls.py @@ -961,7 +942,6 @@ EOF pytest "${PYTEST_REPORTING_ARGS[@]}" \ --hge-urls "$HGE_URL" \ --pg-urls "$HASURA_GRAPHQL_PG_SOURCE_URL_1" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-read-only-source \ test_graphql_read_only_source.py @@ -1011,7 +991,7 @@ post-webhook) WH_PID=$! wait_for_port 9090 - run_pytest_parallel --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" + run_pytest_parallel --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" kill_hge_servers ;; @@ -1028,7 +1008,6 @@ webhook-request-context) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" \ --test-webhook-request-context \ test_webhook_request_context.py @@ -1051,7 +1030,7 @@ get-webhook) WH_PID=$! wait_for_port 9090 - run_pytest_parallel --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" + run_pytest_parallel --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" kill_hge_servers ;; @@ -1077,7 +1056,6 @@ insecure-webhook) wait_for_port 9090 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" \ --test-webhook-insecure \ test_webhook_insecure.py @@ -1105,7 +1083,6 @@ insecure-webhook-with-admin-secret) wait_for_port 9090 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --hge-webhook="$HASURA_GRAPHQL_AUTH_HOOK" \ --test-webhook-insecure \ test_webhook_insecure.py @@ -1124,7 +1101,6 @@ apollo-federation) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_apollo_federation.py unset HASURA_GRAPHQL_EXPERIMENTAL_FEATURES @@ -1142,7 +1118,6 @@ allowlist-queries) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_allowlist_queries.py kill_hge_servers @@ -1157,7 +1132,6 @@ developer-api-tests) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ test_dev_endpoints.py unset HASURA_GRAPHQL_ENABLED_APIS @@ -1187,7 +1161,6 @@ jwk-url) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-jwk-url \ -k 'test_cache_control_header_max_age' @@ -1200,7 +1173,6 @@ jwk-url) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-jwk-url \ -k 'test_cache_control_header_max_age' @@ -1213,7 +1185,6 @@ jwk-url) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-jwk-url \ -k 'test_cache_control_header_no_caching' @@ -1226,7 +1197,6 @@ jwk-url) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-jwk-url \ -k 'test_cache_control_header_no_caching' @@ -1239,7 +1209,6 @@ jwk-url) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-jwk-url \ -k 'test_cache_control_header_no_caching' @@ -1252,7 +1221,6 @@ jwk-url) wait_for_port 8080 pytest "${PYTEST_COMMON_ARGS[@]}" \ - --hge-key="$HASURA_GRAPHQL_ADMIN_SECRET" \ --test-jwk-url \ -k 'test_expires_header' diff --git a/server/tests-py/conftest.py b/server/tests-py/conftest.py index f38609fd87fca..bd30baf72c908 100644 --- a/server/tests-py/conftest.py +++ b/server/tests-py/conftest.py @@ -7,6 +7,7 @@ import threading import time from typing import Optional +import uuid import auth_webhook_server from context import HGECtx, HGECtxGQLServer, ActionsWebhookServer, EvtsWebhookServer, GQLWsClient, PytestConf, GraphQLWSClient @@ -34,9 +35,6 @@ def pytest_addoption(parser): required=False, nargs='+' ) - parser.addoption( - "--hge-key", metavar="HGE_KEY", help="admin secret key for graphql-engine", required=False - ) parser.addoption( "--hge-webhook", metavar="HGE_WEBHOOK", help="url for graphql-engine's access control webhook", required=False ) @@ -85,14 +83,6 @@ def pytest_addoption(parser): help="Run testcases for startup database calls" ) - parser.addoption( - "--test-streaming-subscriptions", - action="store_true", - default=False, - required=False, - help="Run streaming subscription tests" - ) - parser.addoption( "--test-jwk-url", action="store_true", @@ -372,8 +362,23 @@ def hge_fixture_env() -> dict[str, str]: return {} @pytest.fixture(scope='class') -def hge_key(request) -> Optional[str]: - return request.config.getoption('--hge-key') +def hge_key( + request: pytest.FixtureRequest, + hge_bin: Optional[str], +) -> Optional[str]: + marker = request.node.get_closest_marker('admin_secret') + if hge_bin: + # If the test requests an admin secret, generate one. + return str(uuid.uuid4()) if marker else None + else: + # If the environment variable is set, use it. + # This will be used in the event that we start the server outside the test harness. + # We skip the test if it explicitly requires that we have no admin secret. + anti_marker = request.node.get_closest_marker('no_admin_secret') + env_key = os.environ.get('HASURA_GRAPHQL_ADMIN_SECRET') + if anti_marker and env_key: + pytest.skip('This test requires that the admin secret is not set.') + return env_key @pytest.fixture(scope='class') def hge_server( @@ -381,16 +386,28 @@ def hge_server( hge_bin: Optional[str], hge_port: int, hge_url: str, + hge_key: Optional[str], hge_fixture_env: dict[str, str], pg_url: str, ) -> Optional[str]: if not hge_bin: return None - return fixtures.hge.hge_server(request, hge_bin, hge_port, hge_url, hge_fixture_env, pg_url) + return fixtures.hge.hge_server(request, hge_bin, hge_port, hge_url, hge_key, hge_fixture_env, pg_url) + +@pytest.fixture(scope='class') +def enabled_apis(request: pytest.FixtureRequest, hge_bin: Optional[str]) -> Optional[set[str]]: + if hge_bin: + hge_marker_env: dict[str, str] = {marker.args[0]: marker.args[1] for marker in request.node.iter_markers('hge_env') if marker.args[1] is not None} + enabled_apis_str = hge_marker_env.get('HASURA_GRAPHQL_ENABLED_APIS') + else: + enabled_apis_str = os.environ.get('HASURA_GRAPHQL_ENABLED_APIS') + if not enabled_apis_str: + return None + return set(enabled_apis_str.split(',')) @pytest.fixture(scope='class') -def hge_ctx(request, hge_url, pg_url, hge_server): - hge_ctx = HGECtx(hge_url, pg_url, request.config) +def hge_ctx(request, hge_url, pg_url, hge_key, enabled_apis, hge_server): + hge_ctx = HGECtx(hge_url, pg_url, hge_key, enabled_apis, request.config) yield hge_ctx @@ -442,12 +459,6 @@ def auth_hook(hge_fixture_env: dict[str, str]): yield server auth_webhook_server.stop_server(server) -@pytest.fixture(scope='class') -def streaming_subscriptions_fixtures(hge_ctx): - if not hge_ctx.streaming_subscriptions: - pytest.skip('These tests are meant to be run with --test-streaming-subscriptions set with pytest') - return - @pytest.fixture(scope='class') def pro_tests_fixtures(hge_ctx): if not hge_ctx.pro_tests: diff --git a/server/tests-py/context.py b/server/tests-py/context.py index 45cd0608a9749..aff1edc1a9829 100644 --- a/server/tests-py/context.py +++ b/server/tests-py/context.py @@ -790,10 +790,9 @@ def url(self): class HGECtx: - def __init__(self, hge_url, pg_url, config): - + def __init__(self, hge_url, pg_url, hge_key, enabled_apis, config): self.http = requests.Session() - self.hge_key = config.getoption('--hge-key') + self.hge_key = hge_key self.timeout = 120 # BigQuery can take a while self.hge_url = hge_url self.pg_url = pg_url @@ -812,7 +811,6 @@ def __init__(self, hge_url, pg_url, config): self.hge_jwt_algo = "EdDSA" self.webhook_insecure = config.getoption('--test-webhook-insecure') self.may_skip_test_teardown = False - self.streaming_subscriptions = config.getoption('--test-streaming-subscriptions') # This will be GC'd, but we also explicitly dispose() in teardown() self.engine = sqlalchemy.create_engine(self.pg_url) @@ -833,9 +831,6 @@ def __init__(self, hge_url, pg_url, config): self.default_backend = 'postgres' self.is_default_backend = self.backend == self.default_backend - enabled_apis_str = os.environ.get('HASURA_GRAPHQL_ENABLED_APIS') - enabled_apis = set(enabled_apis_str.split(',')) if enabled_apis_str else None - env_version = os.getenv('VERSION') if env_version: self.version = env_version diff --git a/server/tests-py/docker-compose.yml b/server/tests-py/docker-compose.yml index e45ae9af753cd..7e5cd89db612b 100644 --- a/server/tests-py/docker-compose.yml +++ b/server/tests-py/docker-compose.yml @@ -80,6 +80,14 @@ services: volumes: - /var/lib/postgresql/data + citus-healthy: + image: busybox + command: + - 'true' + depends_on: + citus: + condition: service_healthy + mssql: # Uses a different image for arm64. image: ${MSSQL_IMAGE:-mcr.microsoft.com/mssql/server:2019-latest@sha256:a098c9ff6fbb8e1c9608ad7511fa42dba8d22e0d50b48302761717840ccc26af} diff --git a/server/tests-py/fixtures/hge.py b/server/tests-py/fixtures/hge.py index e515936d831a8..23eb630b2f29d 100644 --- a/server/tests-py/fixtures/hge.py +++ b/server/tests-py/fixtures/hge.py @@ -24,6 +24,7 @@ def hge_server( hge_bin: str, hge_port: int, hge_url: str, + hge_key: Optional[str], hge_fixture_env: dict[str, str], pg_url: str, ) -> Optional[str]: @@ -35,6 +36,8 @@ def hge_server( **hge_marker_env, } + hge_key_args = ['--admin-secret', hge_key] if hge_key else [] + print(f'Starting GraphQL Engine on {hge_url}...') hge_process = subprocess.Popen( args = [ @@ -43,6 +46,7 @@ def hge_server( 'serve', '--server-port', str(hge_port), '--stringify-numeric-types', + *hge_key_args, ], env = env, ) diff --git a/server/tests-py/pytest.ini b/server/tests-py/pytest.ini index c4e18e3d6a09d..dfb8edcd002e0 100644 --- a/server/tests-py/pytest.ini +++ b/server/tests-py/pytest.ini @@ -6,6 +6,7 @@ norecursedirs = queries webhook test_upgrade xfail_strict = true markers = backend: The backends supported by the test case + admin_secret: Generate and use an admin secret hge_env: Pass additional environment variables to the GraphQL Engine skip_server_upgrade_test: Tests with this marker should not be run as part of server upgrade test allow_server_upgrade_test: Add tests with this marker to server upgrade test, as far as they don't have the skip_server_upgarde_test market diff --git a/server/tests-py/run-new.sh b/server/tests-py/run-new.sh index 8e974b70654ae..16487fca3d5c2 100755 --- a/server/tests-py/run-new.sh +++ b/server/tests-py/run-new.sh @@ -30,7 +30,7 @@ if [[ "$(uname -m)" == 'arm64' ]]; then fi docker compose rm -svf citus mssql postgres -docker compose up -d citus mssql-healthcheck postgres-healthy +docker compose up -d citus-healthy mssql-healthcheck postgres-healthy HASURA_GRAPHQL_CITUS_SOURCE_URL="postgresql://postgres:hasura@localhost:$(docker compose port citus 5432 | sed -E 's/.*://')/postgres" HASURA_GRAPHQL_MSSQL_SOURCE_URL="DRIVER={ODBC Driver 17 for SQL Server};SERVER=localhost,$(docker compose port mssql 1433 | sed -E 's/.*://');Uid=sa;Pwd=Password!;" diff --git a/server/tests-py/run.sh b/server/tests-py/run.sh index f01de3649c50a..75e88729601d0 100755 --- a/server/tests-py/run.sh +++ b/server/tests-py/run.sh @@ -49,12 +49,12 @@ else fi echo "*** Building HGE ***" -docker compose run hge-build +docker compose run --rm hge-build for SERVER_TEST_TO_RUN in "${SERVER_TESTS_TO_RUN[@]}"; do export SERVER_TEST_TO_RUN echo echo "*** Running test suite: ${SERVER_TEST_TO_RUN} ***" docker compose rm -svf citus mssql postgres # tear down databases beforehand - docker compose run tests-py + docker compose run --rm tests-py done diff --git a/server/tests-py/test_apis_disabled.py b/server/tests-py/test_apis_disabled.py index 627c2c7a326ae..e669482b92f7e 100644 --- a/server/tests-py/test_apis_disabled.py +++ b/server/tests-py/test_apis_disabled.py @@ -6,6 +6,7 @@ pytestmark = [ pytest.mark.usefixtures('auth_hook'), + pytest.mark.admin_secret, pytest.mark.hge_env('HASURA_GRAPHQL_AUTH_HOOK_MODE', 'POST'), ] diff --git a/server/tests-py/test_apollo_federation.py b/server/tests-py/test_apollo_federation.py index 15f67bd7b66bb..02f6dd7d1b8e8 100644 --- a/server/tests-py/test_apollo_federation.py +++ b/server/tests-py/test_apollo_federation.py @@ -12,18 +12,20 @@ def make_request(url, query): resp = requests.post(url, json=payload) return resp -@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', 'apollo_federation') @pytest.mark.usefixtures('per_class_tests_db_state') +@pytest.mark.admin_secret +@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', 'apollo_federation') class TestApolloFederation: @classmethod def dir(cls): return 'queries/apollo_federation' - def test_apollo_federated_server_with_hge_only(self, hge_url: str): + def test_apollo_federated_server_with_hge_only(self, hge_url: str, hge_key: str): # start the node server fed_server = NodeGraphQL(["node", "remote_schemas/nodejs/apollo_federated_server_with_hge_only.js"], env={ 'HGE_URL': hge_url, + 'HASURA_GRAPHQL_ADMIN_SECRET': hge_key, }) fed_server.start() @@ -45,16 +47,16 @@ def test_apollo_federated_server_with_hge_only(self, hge_url: str): assert resp.status_code == 200, resp.text assert 'data' in resp.text - def test_apollo_federated_server_with_hge_and_apollo_graphql_server(self, hge_url: str): + def test_apollo_federated_server_with_hge_and_apollo_graphql_server(self, hge_url: str, hge_key: str): # start the node servers server_1 = NodeGraphQL(["node", "remote_schemas/nodejs/apollo_server_1.js"], env={ 'HGE_URL': hge_url, }) - server_env = { + fed_server = NodeGraphQL(["node", "remote_schemas/nodejs/apollo_federated_server_with_hge_and_server1.js"], env={ 'HGE_URL': hge_url, 'OTHER_URL': server_1.url, - } - fed_server = NodeGraphQL(["node", "remote_schemas/nodejs/apollo_federated_server_with_hge_and_server1.js"], env=server_env) + 'HASURA_GRAPHQL_ADMIN_SECRET': hge_key, + }) server_1.start() fed_server.start() @@ -80,8 +82,8 @@ def test_apollo_federated_server_with_hge_and_apollo_graphql_server(self, hge_ur assert resp.status_code == 200, resp.text assert 'data' in resp.text - def test_apollo_federation_fields(self,hge_ctx): + def test_apollo_federation_fields(self, hge_ctx): check_query_f(hge_ctx, self.dir() + '/root_fields.yaml') - def test_apollo_federation_entities(self,hge_ctx): + def test_apollo_federation_entities(self, hge_ctx): check_query_f(hge_ctx, self.dir() + '/entities.yaml') diff --git a/server/tests-py/test_auth_webhook_cookie.py b/server/tests-py/test_auth_webhook_cookie.py index 2ac364ef137b8..fcf77a8e046f0 100644 --- a/server/tests-py/test_auth_webhook_cookie.py +++ b/server/tests-py/test_auth_webhook_cookie.py @@ -14,6 +14,7 @@ pytest.skip("--test-auth-webhook-header flag is missing, skipping tests", allow_module_level=True) @pytest.mark.usefixtures('auth_hook', 'per_class_tests_db_state') +@pytest.mark.admin_secret class TestWebhookHeaderCookie(object): ''' To run the test, run an instance of the auth_webhook server using `python3 auth_webhook_server.py` diff --git a/server/tests-py/test_compat.py b/server/tests-py/test_compat.py index c652728e84451..bc6324168a127 100644 --- a/server/tests-py/test_compat.py +++ b/server/tests-py/test_compat.py @@ -1,10 +1,6 @@ import pytest -from context import PytestConf -if not PytestConf.config.getoption("--hge-key"): - pytest.skip("--hge-key flag is missing, skipping tests", allow_module_level=True) - -def v1qCompat(hge_ctx, q, headers = {}): +def v1qCompat(hge_ctx, q): h = {'X-Hasura-Access-Key': hge_ctx.hge_key} resp = hge_ctx.http.post( hge_ctx.hge_url + "/v1/query", @@ -13,6 +9,7 @@ def v1qCompat(hge_ctx, q, headers = {}): ) return resp.status_code, resp.json() +@pytest.mark.admin_secret class TestGraphQLCompatAccessKey(): export_metadata = { diff --git a/server/tests-py/test_dev_endpoints.py b/server/tests-py/test_dev_endpoints.py index 5d88bcb33591d..5992f717f7e58 100644 --- a/server/tests-py/test_dev_endpoints.py +++ b/server/tests-py/test_dev_endpoints.py @@ -1,6 +1,5 @@ import requests import pytest -from context import PytestConf """ @@ -25,6 +24,7 @@ def get_headers(hge_ctx, role='admin'): headers['x-hasura-role'] = role return headers +@pytest.mark.admin_secret @pytest.mark.hge_env('HASURA_GRAPHQL_ENABLED_APIS', 'metadata,graphql,developer,config,pgdump') class TestDevEndpoints: diff --git a/server/tests-py/test_graphql_mutations.py b/server/tests-py/test_graphql_mutations.py index ad4cf87191401..00223737fbca7 100644 --- a/server/tests-py/test_graphql_mutations.py +++ b/server/tests-py/test_graphql_mutations.py @@ -798,6 +798,7 @@ def test_delete_where_enum_field(self, hge_ctx, transport): # Tracking VOLATILE SQL functions as mutations, or queries (#1514) @pytest.mark.parametrize('transport', ['http', 'websocket']) @use_mutation_fixtures +@pytest.mark.admin_secret @pytest.mark.hge_env('HASURA_GRAPHQL_INFER_FUNCTION_PERMISSIONS', 'false') class TestGraphQLMutationFunctions: @classmethod diff --git a/server/tests-py/test_graphql_queries.py b/server/tests-py/test_graphql_queries.py index c909d43362f30..922177617c06d 100644 --- a/server/tests-py/test_graphql_queries.py +++ b/server/tests-py/test_graphql_queries.py @@ -1,12 +1,12 @@ -import pytest -from validate import assert_response_code, check_query_f, check_query, get_conf_f -from context import PytestConf - import json -import textwrap +import pytest import ruamel.yaml as yaml +import textwrap import warnings +from context import PytestConf +from validate import assert_response_code, check_query_f, get_conf_f + # Mark that all tests in this module can be run as server upgrade tests pytestmark = pytest.mark.allow_server_upgrade_test @@ -1303,6 +1303,7 @@ def _test_relay_pagination(hge_ctx, transport, test_file_prefix, no_of_pages): @pytest.mark.parametrize('transport', ['http', 'websocket']) @pytest.mark.usefixtures('per_method_tests_db_state') +@pytest.mark.admin_secret @pytest.mark.hge_env('HASURA_GRAPHQL_INFER_FUNCTION_PERMISSIONS', 'false') class TestGraphQLQueryFunctionPermissions: @classmethod diff --git a/server/tests-py/test_jwt.py b/server/tests-py/test_jwt.py index 0459df8b5934f..b597e4f4486d7 100644 --- a/server/tests-py/test_jwt.py +++ b/server/tests-py/test_jwt.py @@ -410,7 +410,7 @@ def gen_rsa_key(): class TestSubscriptionJwtExpiry(object): - def test_jwt_expiry(self, hge_ctx, ws_client): + def test_jwt_expiry(self, hge_ctx, hge_key, ws_client): curr_time = datetime.now() self.claims = { 'sub': '1234567890', @@ -433,7 +433,7 @@ def test_jwt_expiry(self, hge_ctx, ws_client): authz_header = mk_authz_header(hge_ctx.hge_jwt_conf, token) payload = dict() payload['headers'] = authz_header - init_ws_conn(hge_ctx, ws_client, payload) + init_ws_conn(hge_key, ws_client, payload) time.sleep(6) assert ws_client.remote_closed == True, ws_client.remote_closed diff --git a/server/tests-py/test_remote_schema_permissions.py b/server/tests-py/test_remote_schema_permissions.py index 8977eab8cc76a..e2edab7032fa6 100644 --- a/server/tests-py/test_remote_schema_permissions.py +++ b/server/tests-py/test_remote_schema_permissions.py @@ -7,6 +7,7 @@ from validate import check_query_f pytestmark = [ + pytest.mark.admin_secret, pytest.mark.hge_env('HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS', 'true'), ] diff --git a/server/tests-py/test_roles_inheritance.py b/server/tests-py/test_roles_inheritance.py index a3c219d0447b1..b1a7a43c382a7 100644 --- a/server/tests-py/test_roles_inheritance.py +++ b/server/tests-py/test_roles_inheritance.py @@ -6,6 +6,7 @@ from validate import check_query_f pytestmark = [ + pytest.mark.admin_secret, pytest.mark.hge_env('HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS', 'true'), ] diff --git a/server/tests-py/test_subscriptions.py b/server/tests-py/test_subscriptions.py index 954f7f4924fa9..549fe38ceb903 100644 --- a/server/tests-py/test_subscriptions.py +++ b/server/tests-py/test_subscriptions.py @@ -1,111 +1,104 @@ -#!/usr/bin/env python3 - -import datetime -import time -import pytest +from collections import OrderedDict import json +import pytest import queue +from ruamel.yaml import YAML +import time +import uuid + from validate import check_query_f -from collections import OrderedDict from utils import insert_many -from ruamel.yaml import YAML -usefixtures = pytest.mark.usefixtures yaml=YAML(typ='safe', pure=True) +usefixtures = pytest.mark.usefixtures + @pytest.fixture(scope='class') -def ws_conn_init(hge_ctx, ws_client): - init_ws_conn(hge_ctx, ws_client) +def ws_conn_init(hge_key, ws_client): + init_ws_conn(hge_key, ws_client) @pytest.fixture(scope='class') -def ws_conn_init_graphql_ws(hge_ctx, ws_client_graphql_ws): - init_graphql_ws_conn(hge_ctx, ws_client_graphql_ws) +def ws_conn_init_graphql_ws(hge_key, ws_client_graphql_ws): + init_graphql_ws_conn(hge_key, ws_client_graphql_ws) ''' Refer: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_connection_init ''' -def init_ws_conn(hge_ctx, ws_client, payload = None): - if payload is None: - payload = {} - if hge_ctx.hge_key is not None: - payload = { - 'headers' : { - 'X-Hasura-Admin-Secret': hge_ctx.hge_key - } - } - +# This is used in other test files! Be careful when modifying it. +def init_ws_conn(hge_key, ws_client, payload = None): init_msg = { 'type': 'connection_init', - 'payload': payload, + 'payload': payload or ws_payload(hge_key), } ws_client.send(init_msg) ev = ws_client.get_ws_event(3) assert ev['type'] == 'connection_ack', ev -def init_graphql_ws_conn(hge_ctx, ws_client_graphql_ws, payload = None): - if payload is None: - payload = {} - if hge_ctx.hge_key is not None: - payload = { - 'headers' : { - 'X-Hasura-Admin-Secret': hge_ctx.hge_key - } - } - +def init_graphql_ws_conn(hge_key, ws_client_graphql_ws): init_msg = { 'type': 'connection_init', - 'payload': payload, + 'payload': ws_payload(hge_key), } ws_client_graphql_ws.send(init_msg) ev = ws_client_graphql_ws.get_ws_event(3) assert ev['type'] == 'connection_ack', ev -def get_explain_graphql_query_response(hge_ctx, query, variables, user_headers = {}): - admin_secret = hge_ctx.hge_key +def ws_payload(hge_key): + if hge_key is not None: + return { + 'headers': { + 'X-Hasura-Admin-Secret': hge_key, + } + } + else: + return {} + +def get_explain_graphql_query_response(hge_ctx, hge_key, query, variables, user_headers = {}): headers = {} - if admin_secret is not None: - headers['X-Hasura-Admin-Secret'] = admin_secret + if hge_key is not None: + headers['X-Hasura-Admin-Secret'] = hge_key request = { 'query': { 'query': query, 'variables': variables }, 'user': user_headers } status_code, response, _ = hge_ctx.anyq('/v1/graphql/explain', request, headers) assert status_code == 200, (request, status_code, response) return response -class TestSubscriptionCtrl(object): +@pytest.mark.no_admin_secret +class TestSubscriptionCtrlWithoutSecret(object): + def test_connection(self, ws_client): + ws_client.recreate_conn() + init_ws_conn(None, ws_client) - def test_init_without_payload(self, hge_ctx, ws_client): - if hge_ctx.hge_key is not None: - pytest.skip("Payload is needed when admin secret is set") - init_msg = { - 'type': 'connection_init' + obj = { + 'type': 'connection_terminate' } - ws_client.send(init_msg) - ev = ws_client.get_ws_event(15) - assert ev['type'] == 'connection_ack', ev - + ws_client.send(obj) + with pytest.raises(queue.Empty): + ws_client.get_ws_event(3) +@pytest.mark.admin_secret +class TestSubscriptionCtrl(object): ''' - Refer: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_connection_init + References: + https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_connection_init + https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_connection_terminate ''' - def test_init(self, hge_ctx, ws_client): - init_ws_conn(hge_ctx, ws_client) + def test_connection(self, hge_key, ws_client): + ws_client.recreate_conn() + init_ws_conn(hge_key, ws_client) - ''' - Refer: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_connection_terminate - ''' - - def test_connection_terminate(self, hge_ctx, ws_client): obj = { 'type': 'connection_terminate' } ws_client.send(obj) with pytest.raises(queue.Empty): - ev = ws_client.get_ws_event(3) + ws_client.get_ws_event(3) @pytest.mark.backend('mssql', 'postgres') @usefixtures('per_class_tests_db_state', 'ws_conn_init') +@pytest.mark.admin_secret class TestSubscriptionBasic: @classmethod def dir(cls): @@ -129,6 +122,7 @@ def test_connection_error(self, ws_client): ''' def test_start(self, ws_client): + id = str(uuid.uuid4()) query = """ subscription { hge_tests_test_t1(order_by: {c1: desc}, limit: 1) { @@ -138,7 +132,7 @@ def test_start(self, ws_client): } """ obj = { - 'id': '1', + 'id': id, 'payload': { 'query': query }, @@ -148,13 +142,13 @@ def test_start(self, ws_client): ''' Refer: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_data ''' - ev = ws_client.get_ws_query_event('1',15) - assert ev['type'] == 'data' and ev['id'] == '1', ev + ev = ws_client.get_ws_query_event(id, 15) + assert ev['type'] == 'data' and ev['id'] == id, ev ''' Refer https://github.com/apollographql/subscriptions-transport-ws/blob/01e0b2b65df07c52f5831cce5c858966ba095993/src/server.ts#L306 ''' - @pytest.mark.skip(reason="refer https://github.com/hasura/graphql-engine/pull/387#issuecomment-421343098") + @pytest.mark.skip(reason="refer to https://github.com/hasura/graphql-engine/pull/387#issuecomment-421343098") def test_start_duplicate(self, ws_client): self.test_start(ws_client) @@ -187,7 +181,7 @@ def test_start_after_stop(self, ws_client): Refer: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_complete ''' - def test_complete(self, hge_ctx, ws_client): + def test_complete(self, ws_client): query = """ query { hge_tests_test_t1(order_by: {c1: desc}, limit: 1) { @@ -215,6 +209,7 @@ def test_complete(self, hge_ctx, ws_client): ## FIXME: There's an issue with the tests being parametrized with both ## postgres and mssql data sources enabled(See issue #2084). @usefixtures('per_method_tests_db_state', 'ws_conn_init_graphql_ws') +@pytest.mark.admin_secret class TestSubscriptionBasicGraphQLWS: @classmethod def dir(cls): @@ -224,10 +219,10 @@ def dir(cls): def test_negative(self, hge_ctx, transport): check_query_f(hge_ctx, self.dir() + '/negative_test.yaml', transport, gqlws=True) - def test_connection_error(self, hge_ctx, ws_client_graphql_ws): + def test_connection_error(self, hge_key, ws_client_graphql_ws): if ws_client_graphql_ws.get_conn_close_state(): ws_client_graphql_ws.create_conn() - if hge_ctx.hge_key == None: + if hge_key == None: ws_client_graphql_ws.init() else: ws_client_graphql_ws.init_as_admin() @@ -236,13 +231,15 @@ def test_connection_error(self, hge_ctx, ws_client_graphql_ws): ev = ws_client_graphql_ws.get_conn_close_state() assert ev == True, ev - def test_start(self, hge_ctx, ws_client_graphql_ws): + def test_start(self, hge_key, ws_client_graphql_ws): if ws_client_graphql_ws.get_conn_close_state(): ws_client_graphql_ws.create_conn() - if hge_ctx.hge_key == None: + if hge_key == None: ws_client_graphql_ws.init() else: ws_client_graphql_ws.init_as_admin() + + id = str(uuid.uuid4()) query = """ subscription { hge_tests_test_t1(order_by: {c1: desc}, limit: 1) { @@ -252,30 +249,30 @@ def test_start(self, hge_ctx, ws_client_graphql_ws): } """ obj = { - 'id': '1', + 'id': id, 'payload': { 'query': query }, 'type': 'subscribe' } ws_client_graphql_ws.send(obj) - ev = ws_client_graphql_ws.get_ws_query_event('1',15) - assert ev['type'] == 'next' and ev['id'] == '1', ev + ev = ws_client_graphql_ws.get_ws_query_event(id, 15) + assert ev['type'] == 'next' and ev['id'] == id, ev - @pytest.mark.skip(reason="refer https://github.com/hasura/graphql-engine/pull/387#issuecomment-421343098") - def test_start_duplicate(self, hge_ctx, ws_client_graphql_ws): + @pytest.mark.skip(reason="refer to https://github.com/hasura/graphql-engine/pull/387#issuecomment-421343098") + def test_start_duplicate(self, hge_key, ws_client_graphql_ws): if ws_client_graphql_ws.get_conn_close_state(): ws_client_graphql_ws.create_conn() - if hge_ctx.hge_key == None: + if hge_key == None: ws_client_graphql_ws.init() else: ws_client_graphql_ws.init_as_admin() - self.test_start(ws_client_graphql_ws) + self.test_start(hge_key, ws_client_graphql_ws) - def test_stop_without_id(self, hge_ctx, ws_client_graphql_ws): + def test_stop_without_id(self, hge_key, ws_client_graphql_ws): if ws_client_graphql_ws.get_conn_close_state(): ws_client_graphql_ws.create_conn() - if hge_ctx.hge_key == None: + if hge_key == None: ws_client_graphql_ws.init() else: ws_client_graphql_ws.init_as_admin() @@ -287,10 +284,10 @@ def test_stop_without_id(self, hge_ctx, ws_client_graphql_ws): ev = ws_client_graphql_ws.get_conn_close_state() assert ev == True, ev - def test_stop(self, hge_ctx, ws_client_graphql_ws): + def test_stop(self, hge_key, ws_client_graphql_ws): if ws_client_graphql_ws.get_conn_close_state(): ws_client_graphql_ws.create_conn() - if hge_ctx.hge_key == None: + if hge_key == None: ws_client_graphql_ws.init() else: ws_client_graphql_ws.init_as_admin() @@ -303,10 +300,10 @@ def test_stop(self, hge_ctx, ws_client_graphql_ws): with pytest.raises(queue.Empty): ev = ws_client_graphql_ws.get_ws_event(3) - def test_start_after_stop(self, hge_ctx, ws_client_graphql_ws): + def test_start_after_stop(self, hge_key, hge_ctx, ws_client_graphql_ws): if ws_client_graphql_ws.get_conn_close_state(): ws_client_graphql_ws.create_conn() - if hge_ctx.hge_key == None: + if hge_key == None: ws_client_graphql_ws.init() else: ws_client_graphql_ws.init_as_admin() @@ -316,10 +313,11 @@ def test_start_after_stop(self, hge_ctx, ws_client_graphql_ws): ws_client_graphql_ws.clear_queue() self.test_stop(hge_ctx, ws_client_graphql_ws) - def test_complete(self, hge_ctx, ws_client_graphql_ws): + def test_complete(self, hge_key, ws_client_graphql_ws): + id = str(uuid.uuid4()) if ws_client_graphql_ws.get_conn_close_state(): ws_client_graphql_ws.create_conn() - if hge_ctx.hge_key == None: + if hge_key == None: ws_client_graphql_ws.init() else: ws_client_graphql_ws.init_as_admin() @@ -332,27 +330,28 @@ def test_complete(self, hge_ctx, ws_client_graphql_ws): } """ obj = { - 'id': '2', + 'id': id, 'payload': { 'query': query }, 'type': 'subscribe' } ws_client_graphql_ws.send(obj) - ev = ws_client_graphql_ws.get_ws_query_event('2',3) - assert ev['type'] == 'next' and ev['id'] == '2', ev + ev = ws_client_graphql_ws.get_ws_query_event(id, 3) + assert ev['type'] == 'next' and ev['id'] == id, ev # Check for complete type - ev = ws_client_graphql_ws.get_ws_query_event('2',3) - assert ev['type'] == 'complete' and ev['id'] == '2', ev + ev = ws_client_graphql_ws.get_ws_query_event(id, 3) + assert ev['type'] == 'complete' and ev['id'] == id, ev @usefixtures('per_method_tests_db_state','ws_conn_init') +@pytest.mark.admin_secret class TestSubscriptionLiveQueries: @classmethod def dir(cls): return 'queries/subscriptions/live_queries' - def test_live_queries(self, hge_ctx, ws_client): + def test_live_queries(self, hge_key, ws_client): ''' Create connection using connection_init ''' @@ -375,8 +374,8 @@ def test_live_queries(self, hge_ctx, ws_client): for i, resultLimit in queries: query = queryTmplt.replace('{0}',str(i)) headers={} - if hge_ctx.hge_key is not None: - headers['X-Hasura-Admin-Secret'] = hge_ctx.hge_key + if hge_key is not None: + headers['X-Hasura-Admin-Secret'] = hge_key subscrPayload = { 'query': query, 'variables': { 'result_limit': resultLimit } } respLive = ws_client.send_query(subscrPayload, query_id='live_'+str(i), headers=headers, timeout=15) liveQs.append(respLive) @@ -427,14 +426,15 @@ def test_live_queries(self, hge_ctx, ws_client): with pytest.raises(queue.Empty): ev = ws_client.get_ws_event(3) -@usefixtures('per_method_tests_db_state','ws_conn_init','streaming_subscriptions_fixtures') +@usefixtures('per_method_tests_db_state', 'ws_conn_init') +@pytest.mark.hge_env('HASURA_GRAPHQL_EXPERIMENTAL_FEATURES', 'streaming_subscriptions') class TestStreamingSubscription: @classmethod def dir(cls): return 'queries/subscriptions/streaming' - def test_basic_streaming_subscription_existing_static_data(self, hge_ctx, ws_client): + def test_basic_streaming_subscription_existing_static_data(self, hge_key, hge_ctx, ws_client): ''' Create connection using connection_init ''' @@ -455,8 +455,8 @@ def test_basic_streaming_subscription_existing_static_data(self, hge_ctx, ws_cli for i in range(10): articles_to_insert.append({"id": i + 1, "title": "Article title {}".format(i + 1)}) insert_many(hge_ctx, {"schema": "hge_tests", "name": "articles"}, articles_to_insert) - if hge_ctx.hge_key is not None: - headers['X-Hasura-Admin-Secret'] = hge_ctx.hge_key + if hge_key is not None: + headers['X-Hasura-Admin-Secret'] = hge_key subscrPayload = { 'query': query, 'variables': { 'batch_size': 2 } } respLive = ws_client.send_query(subscrPayload, query_id='stream_1', headers=headers, timeout=15) liveQs.append(respLive) @@ -478,7 +478,7 @@ def test_basic_streaming_subscription_existing_static_data(self, hge_ctx, ws_cli with pytest.raises(queue.Empty): ev = ws_client.get_ws_event(3) - def test_streaming_subscriptions_with_concurrent_data_inserts(self, hge_ctx, ws_client): + def test_streaming_subscriptions_with_concurrent_data_inserts(self, ws_client): ''' Create connection using connection_init ''' @@ -534,7 +534,7 @@ def test_streaming_subscriptions_with_concurrent_data_inserts(self, hge_ctx, ws_ with pytest.raises(queue.Empty): ev = ws_client.get_ws_event(3) - def test_streaming_subscription_with_custom_name_set_for_cursor(self, hge_ctx, ws_client): + def test_streaming_subscription_with_custom_name_set_for_cursor(self, hge_key, ws_client): ''' Create connection using connection_init ''' @@ -551,8 +551,8 @@ def test_streaming_subscription_with_custom_name_set_for_cursor(self, hge_ctx, w liveQs = [] headers={} - if hge_ctx.hge_key is not None: - headers['X-Hasura-Admin-Secret'] = hge_ctx.hge_key + if hge_key is not None: + headers['X-Hasura-Admin-Secret'] = hge_key subscrPayload = { 'query': query, 'variables': { 'batch_size': 1 } } respLive = ws_client.send_query(subscrPayload, query_id='stream_1', headers=headers, timeout=15) liveQs.append(respLive) @@ -574,16 +574,15 @@ def test_streaming_subscription_with_custom_name_set_for_cursor(self, hge_ctx, w with pytest.raises(queue.Empty): ev = ws_client.get_ws_event(3) - - -@usefixtures('per_method_tests_db_state','ws_conn_init_graphql_ws') +@usefixtures('per_method_tests_db_state', 'ws_conn_init_graphql_ws') +@pytest.mark.admin_secret class TestSubscriptionLiveQueriesForGraphQLWS: @classmethod def dir(cls): return 'queries/subscriptions/live_queries' - def test_live_queries(self, hge_ctx, ws_client_graphql_ws): + def test_live_queries(self, hge_key, ws_client_graphql_ws): ''' Create connection using connection_init ''' @@ -606,8 +605,8 @@ def test_live_queries(self, hge_ctx, ws_client_graphql_ws): for i, resultLimit in queries: query = queryTmplt.replace('{0}',str(i)) headers={} - if hge_ctx.hge_key is not None: - headers['X-Hasura-Admin-Secret'] = hge_ctx.hge_key + if hge_key is not None: + headers['X-Hasura-Admin-Secret'] = hge_key subscrPayload = { 'query': query, 'variables': { 'result_limit': resultLimit } } respLive = ws_client_graphql_ws.send_query(subscrPayload, query_id='live_'+str(i), headers=headers, timeout=15) liveQs.append(respLive) @@ -658,13 +657,14 @@ def test_live_queries(self, hge_ctx, ws_client_graphql_ws): @pytest.mark.backend('mssql', 'postgres') @usefixtures('per_class_tests_db_state') +@pytest.mark.admin_secret class TestSubscriptionMultiplexingPostgresMSSQL: @classmethod def dir(cls): return 'queries/subscriptions/multiplexing' - def test_extraneous_session_variables_are_discarded_from_query(self, hge_ctx): + def test_extraneous_session_variables_are_discarded_from_query(self, hge_key, hge_ctx): with open(self.dir() + '/articles_query.yaml') as c: config = yaml.load(c) @@ -673,7 +673,7 @@ def test_extraneous_session_variables_are_discarded_from_query(self, hge_ctx): "X-Hasura-Role":"public", "X-Hasura-User-Id":"1" # extraneous session variable } - response = get_explain_graphql_query_response(hge_ctx, query, {}, session_variables) + response = get_explain_graphql_query_response(hge_ctx, hge_key, query, {}, session_variables) # The input session variables should be ignored because the only check for the role is # if `is_public` is `true` assert response["variables"]["session"] == {}, response["variables"] @@ -683,35 +683,37 @@ def test_extraneous_session_variables_are_discarded_from_query(self, hge_ctx): "X-Hasura-User-Id":"1", "X-Hasura-Allowed-Ids":"{1,3,4}" # extraneous session variable } - response = get_explain_graphql_query_response(hge_ctx, query, {}, session_variables) + response = get_explain_graphql_query_response(hge_ctx, hge_key, query, {}, session_variables) # The input session variable should not be ignored because the `user` role can only # select those roles where `user_id = X-Hasura-User-Id` assert response["variables"]["session"] == {'x-hasura-user-id':"1"}, response["variables"] # test case for https://github.com/hasura/graphql-engine-mono/issues/3689 @usefixtures('per_class_tests_db_state') +@pytest.mark.admin_secret class TestSubscriptionMultiplexingPostgres: @classmethod def dir(cls): return 'queries/subscriptions/multiplexing' - def test_simple_variables_are_parameterized(self, hge_ctx): + def test_simple_variables_are_parameterized(self, hge_key, hge_ctx): with open(self.dir() + '/articles_query_simple_variable.yaml') as c: config = yaml.load(c) - response = get_explain_graphql_query_response(hge_ctx, config['query'], config['variables'], {}) + response = get_explain_graphql_query_response(hge_ctx, hge_key, config['query'], config['variables'], {}) assert response["variables"]["synthetic"] == ['1'], response["variables"] - def test_array_variables_are_parameterized(self, hge_ctx): + def test_array_variables_are_parameterized(self, hge_key, hge_ctx): with open(self.dir() + '/articles_query_array_variable.yaml') as c: config = yaml.load(c) - response = get_explain_graphql_query_response(hge_ctx, config['query'], config['variables'], {}) + response = get_explain_graphql_query_response(hge_ctx, hge_key, config['query'], config['variables'], {}) assert response["variables"]["synthetic"] == ['{1,2,3}'], response["variables"] @pytest.mark.backend('postgres') @usefixtures('per_class_tests_db_state', 'ws_conn_init') +@pytest.mark.admin_secret class TestSubscriptionUDFWithSessionArg: """ Test a user-defined function which uses the entire session variables as argument @@ -730,11 +732,11 @@ class TestSubscriptionUDFWithSessionArg: def dir(cls): return 'queries/subscriptions/udf_session_args' - def test_user_defined_function_with_session_argument(self, hge_ctx, ws_client): + def test_user_defined_function_with_session_argument(self, hge_key, ws_client): ws_client.init_as_admin() headers = {'x-hasura-role': 'user', 'x-hasura-user-id': '42'} - if hge_ctx.hge_key is not None: - headers['X-Hasura-Admin-Secret'] = hge_ctx.hge_key + if hge_key is not None: + headers['X-Hasura-Admin-Secret'] = hge_key payload = {'query': self.query} resp = ws_client.send_query(payload, headers=headers, timeout=15) ev = next(resp) @@ -743,6 +745,7 @@ def test_user_defined_function_with_session_argument(self, hge_ctx, ws_client): @pytest.mark.backend('mssql', 'postgres') @usefixtures('per_class_tests_db_state', 'ws_conn_init') +@pytest.mark.admin_secret class TestSubscriptionCustomizedSourceMSSQLPostgres: @classmethod def dir(cls): @@ -754,7 +757,8 @@ def dir(cls): Refer: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_complete ''' - def test_complete(self, hge_ctx, ws_client): + def test_complete(self, ws_client): + id = str(uuid.uuid4()) query = """ subscription MySubscription { a: my_source { @@ -766,7 +770,7 @@ def test_complete(self, hge_ctx, ws_client): } """ obj = { - 'id': '1', + 'id': id, 'payload': { 'query': query }, @@ -776,11 +780,11 @@ def test_complete(self, hge_ctx, ws_client): ''' Refer: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md#gql_data ''' - ev = ws_client.get_ws_query_event('1',15) - assert ev['type'] == 'data' and ev['id'] == '1', ev + ev = ws_client.get_ws_query_event(id, 15) + assert ev['type'] == 'data' and ev['id'] == id, ev assert ev['payload']['data']['a'] == OrderedDict([('b', [OrderedDict([('id', 1), ('name', 'Author 1')]), OrderedDict([('id', 2), ('name', 'Author 2')])])]), ev - def test_double_alias(self, hge_ctx, ws_client): + def test_double_alias(self, ws_client): ''' This should give an error even though @_multiple_top_level_fields is specified. The two different aliases for `my_source` mean that we would have to wrap different @@ -819,6 +823,7 @@ def test_double_alias(self, hge_ctx, ws_client): @pytest.mark.backend('mssql') @usefixtures('per_class_tests_db_state', 'ws_conn_init') +@pytest.mark.admin_secret class TestSubscriptionMSSQLChunkedResults: @classmethod def dir(cls): diff --git a/server/tests-py/test_webhook.py b/server/tests-py/test_webhook.py index 4bfe6f6f8111c..ab51268b34309 100644 --- a/server/tests-py/test_webhook.py +++ b/server/tests-py/test_webhook.py @@ -19,7 +19,7 @@ def ws_conn_recreate(ws_client): ws_client.recreate_conn() -def connect_with(hge_ctx, ws_client, headers): +def connect_with(hge_key, ws_client, headers): headers['X-Hasura-Role'] = 'user' headers['X-Hasura-User-Id'] = '1234321' headers['X-Hasura-Auth-Mode'] = 'webhook' @@ -27,22 +27,22 @@ def connect_with(hge_ctx, ws_client, headers): token = base64.b64encode(json.dumps(headers).encode('utf-8')).decode('utf-8') headers['Authorization'] = 'Bearer ' + token payload = {'headers': headers} - init_ws_conn(hge_ctx, ws_client, payload) + init_ws_conn(hge_key, ws_client, payload) EXPIRE_TIME_FORMAT = '%a, %d %b %Y %T GMT' @usefixtures('ws_conn_recreate') class TestWebhookSubscriptionExpiry(object): - def test_expiry_with_no_header(self, hge_ctx, ws_client): + def test_expiry_with_no_header(self, hge_key, ws_client): # no expiry time => the connextion will remain alive - connect_with(hge_ctx, ws_client, {}) + connect_with(hge_key, ws_client, {}) time.sleep(5) assert ws_client.remote_closed == False, ws_client.remote_closed - def test_expiry_with_expires_header(self, hge_ctx, ws_client): + def test_expiry_with_expires_header(self, hge_key, ws_client): exp = datetime.utcnow() + timedelta(seconds=6) - connect_with(hge_ctx, ws_client, { + connect_with(hge_key, ws_client, { 'Expires': exp.strftime(EXPIRE_TIME_FORMAT) }) time.sleep(4) @@ -50,8 +50,8 @@ def test_expiry_with_expires_header(self, hge_ctx, ws_client): time.sleep(4) assert ws_client.remote_closed == True, ws_client.remote_closed - def test_expiry_with_cache_control(self, hge_ctx, ws_client): - connect_with(hge_ctx, ws_client, { + def test_expiry_with_cache_control(self, hge_key, ws_client): + connect_with(hge_key, ws_client, { 'Cache-Control': 'max-age=6' }) time.sleep(4) @@ -59,9 +59,9 @@ def test_expiry_with_cache_control(self, hge_ctx, ws_client): time.sleep(4) assert ws_client.remote_closed == True, ws_client.remote_closed - def test_expiry_with_both(self, hge_ctx, ws_client): + def test_expiry_with_both(self, hge_key, ws_client): exp = datetime.utcnow() + timedelta(seconds=6) - connect_with(hge_ctx, ws_client, { + connect_with(hge_key, ws_client, { 'Expires': exp.strftime(EXPIRE_TIME_FORMAT), 'Cache-Control': 'max-age=10', }) @@ -73,12 +73,12 @@ def test_expiry_with_both(self, hge_ctx, ws_client): time.sleep(4) assert ws_client.remote_closed == True, ws_client.remote_closed - def test_expiry_with_parse_error(self, hge_ctx, ws_client): + def test_expiry_with_parse_error(self, hge_key, ws_client): exp = datetime.utcnow() + timedelta(seconds=3) - connect_with(hge_ctx, ws_client, { + connect_with(hge_key, ws_client, { 'Expires': exp.strftime('%a, %d %m %Y %T UTC'), 'Cache-Control': 'maxage=3', }) # neither will parse, the connection will remain alive time.sleep(5) - assert ws_client.remote_closed == False, ws_client.remote_closed \ No newline at end of file + assert ws_client.remote_closed == False, ws_client.remote_closed