graphql-engine/server/tests-py/test_graphql_read_only_source.py
Samir Talwar 7c452bfca1 server/tests-py: Spawn a new PostgreSQL schema ("database") per test.
When running using the "new" style (with a HGE binary, not a URL), a new PostgreSQL metadata and source database are created for each test. When we get this into CI, this should drastically reduce the flakiness.

I have also enabled parallelization by default when using `run-new.sh`. It's much faster.

I had to basically rewrite _server/tests-py/test_graphql_read_only_source.py_ so that it does two different things depending on how it's run. It's unfortunate, but it should eventually go away.

PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6879
GitOrigin-RevId: a121b9035f8da3e61a3e36d8b1fbc6ccae918fad
2022-11-15 19:08:53 +00:00

123 lines
4.5 KiB
Python

import os
import pytest
import sqlalchemy
from typing import Optional
import urllib.parse
from context import HGECtx, PytestConf
import fixtures.postgres
from validate import check_query_f
# Mark that all tests in this module can be run as server upgrade tests
pytestmark = pytest.mark.allow_server_upgrade_test
usefixtures = pytest.mark.usefixtures
if not PytestConf.config.getoption('--test-read-only-source'):
pytest.skip('--test-read-only-source flag is missing, skipping read-only tests',
allow_module_level=True)
@pytest.mark.parametrize('transport', ['http', 'websocket'])
@pytest.mark.backend('postgres', 'citus')
@pytest.mark.admin_secret
@pytest.mark.hge_env('HASURA_GRAPHQL_ADMIN_INTERNAL_ERRORS', 'false')
@usefixtures('setup_schema_externally')
class TestGraphQLOnReadOnlySource:
@classmethod
def dir(cls):
return 'queries/graphql_query/read_only_source'
setup_metadata_api_version = 'v2'
def test_query_aves(self, hge_ctx, transport):
check_query_f(hge_ctx, self.dir() + '/select_query_aves.yaml', transport)
# graphql-engine's websocket response is different than in http on execution
# errors; so this test is run only on http
def test_mutation_aves(self, hge_ctx, transport):
check_query_f(hge_ctx, self.dir() + '/update_query_aves.yaml', 'http')
# As this is a read-only test, we can't create the schema/tables as part of the
# HGE metadata. Hence, we create it as a separate fixture, where we execute the
# DDLs directly on the database.
@pytest.fixture(scope='class')
def setup_schema_externally(
owner_engine: sqlalchemy.engine.Engine,
hge_ctx: HGECtx,
source_backend: Optional[fixtures.postgres.Backend],
):
# TODO: remove once parallelization work is completed
# just use the default source, and get rid of this environment variable entirely
readonly_db_url = os.getenv('HASURA_READONLY_DB_URL')
if source_backend:
engine = source_backend.engine
elif readonly_db_url:
engine = fixtures.postgres.switch_schema(owner_engine, urllib.parse.urlparse(readonly_db_url).path.lstrip('/'))
else:
raise Exception('No database available.')
source = 'default'
# TODO: remove once parallelization work is completed
if readonly_db_url:
source = 'pg_readonly'
hge_ctx.v1metadataq({
'type': 'pg_add_source',
'args': {
'name': source,
'configuration': {
'connection_info': {
'database_url': {
'from_env': 'HASURA_READONLY_DB_URL',
},
},
},
},
})
with engine.connect() as connection:
connection.execute("CREATE TABLE aves (id serial PRIMARY KEY, name TEXT)")
connection.execute("INSERT INTO aves (name) VALUES ('Booted Eagle'), ('Hooded Merganser')")
# TODO: remove once parallelization work is completed
# `source_backend` will no longer be optional
if source_backend:
# Revoke all write privileges from the given user
with fixtures.postgres.switch_schema(owner_engine, source_backend.name).connect() as connection:
username = source_backend.engine.url.username
connection.execute(f'REVOKE ALL PRIVILEGES ON SCHEMA public FROM {username}')
connection.execute(f'REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM {username}')
connection.execute(f'GRANT USAGE ON SCHEMA public TO {username}')
connection.execute(f'GRANT SELECT ON ALL TABLES IN SCHEMA public TO {username}')
connection.execute(f'GRANT SELECT ON ALL TABLES IN SCHEMA pg_catalog TO {username}')
connection.execute(f'GRANT SELECT ON ALL TABLES IN SCHEMA information_schema TO {username}')
connection.execute(f'ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO {username}')
hge_ctx.v1metadataq({
'type': 'pg_track_table',
'args': {
'source': source,
'table': {
'name': 'aves',
},
},
})
yield
# TODO: remove once parallelization work is completed
if readonly_db_url:
hge_ctx.v1metadataq({
'type': 'pg_drop_source',
'args': {
'name': source,
},
})
# TODO: remove once parallelization work is completed
# we can just drop the whole database
with engine.connect() as connection:
connection.execute('DROP TABLE aves')