import os import re import secrets import string import subprocess from collections import defaultdict from pathlib import Path from typing import Dict, Any, Optional, Callable import pytest import yaml @pytest.fixture(scope="session") def user_id(): return "8196299d-f1df-4bcc-8b65-3fcc26df35f5" @pytest.fixture(scope="session") def email(): return "test@fansifter.com" @pytest.fixture(scope="session") def company_schema(): return "c52d1e9c4e756bd99dbc73dc71e953f20e66d1574d42e0cb83ff56945" @pytest.fixture(scope="session") def workspace_schema(): return "wa99431bd38595c7f1da66f56c450a52b16211ebd116c7af1eef03641" @pytest.fixture(scope="session") def alliance_schema(): return "a9c583e82714fd4826e918ddb8953d2655a668feadc0645576cfe9258" @pytest.fixture(scope="session") def merch_collection_id(company_schema): collection_id = 1 return f"{company_schema}-{collection_id}" @pytest.fixture(scope="session") def mailing_list_collection_id(company_schema): collection_id = 41 return f"{company_schema}-{collection_id}" @pytest.fixture(scope="session") def unlabeled_collection_id(company_schema): collection_id = 56 return f"{company_schema}-{collection_id}" @pytest.fixture(scope="session") def alliance_merch_collection_id(alliance_schema): collection_id = 1 return f"{alliance_schema}-{collection_id}" @pytest.fixture(scope="function") def random_string() -> str: return "".join(secrets.choice(string.ascii_lowercase) for _ in range(6)) def pytest_sessionstart(session: pytest.Session): workdir = Path(__file__).parents[1] result = subprocess.run( [ str((workdir / "node_modules/.bin/serverless").resolve()), "print", "--stage", "devel", ], stdout=subprocess.PIPE, cwd=workdir.resolve(), ) config = yaml.safe_load(result.stdout) os.environ.update(config["provider"]["environment"]) pytest.serverless_config = config @pytest.fixture(scope="session") def resolvers() -> Dict[str, Dict[str, Dict[str, str]]]: resources_map = {} for resources_module in pytest.serverless_config["resources"]: resources_map.update(resources_module.get("Resources", {})) resolver_map = defaultdict(lambda: {}) for resource_name, resource_config in resources_map.items(): if resource_config["Type"] == "AWS::AppSync::Resolver": props = resource_config["Properties"] field_name = props["FieldName"] type_name = props["TypeName"] request_template = props["RequestMappingTemplate"] # it's written in VTL, so it seems simpler to use regex here endpoint = re.search(r'"endpoint":\s*"(\S+)"', request_template) if endpoint is not None: resolver_map[type_name][field_name] = dict( type=type_name, endpoint=endpoint.group(1), field=field_name, ) return resolver_map @pytest.fixture(scope="session") def graphql_request(resolvers, user_id) -> Callable: from python import internal_requests def make_graphql_request( field_name: str, arguments: Optional[Dict] = None, type_name: Optional[str] = None, context: Optional[Dict] = None, ) -> Optional[Any]: arguments = arguments or {} context = context or {} if type_name is None: resolver = resolvers["Query"].get(field_name) or resolvers["Mutation"].get( field_name ) else: resolver = resolvers[type_name].get(field_name) if resolver is None: raise ValueError(f"Resolver {type_name}/{field_name} not found.") event = { "field": field_name, "endpoint": resolver["endpoint"], "arguments": arguments, "userSub": user_id, } response = internal_requests.lambda_handler(event, context) if isinstance(response, dict) and 'error' in response: raise RuntimeError(response['error']) else: return response return make_graphql_request