from datetime import datetime, timezone from typing import List from unittest.mock import Mock import os import logging from jose import jwt from sqlalchemy import Table from werkzeug.wrappers import BaseResponse from app import app, db from tests.test_utils import bearer from models import User import softest import glob from os.path import dirname, basename, isfile from tests.test_utils import FixtureLoader from models import models from config import DECIBEL_M2M_ATLAS_BRIDGE_AUDIENCE modules = glob.glob(dirname(__file__) + "/*.py") __all__ = [basename(f)[:-3] for f in modules if isfile(f) and not f.endswith("__init__.py")] class BaseTestCase(softest.TestCase): headers = {"Content-type": "application/json", "Authorization": bearer} fixture = None maxDiff = None @property def app(self): return app @property def client(self): return self.app.test_client() def execute_post(self, *args, **kw): response = self.client.post(*args, **kw) self.__handle_request_response(response) return response def execute_put(self, *args, **kw): response = self.client.put(*args, **kw) self.__handle_request_response(response) return response def execute_patch(self, *args, **kw): response = self.client.patch(*args, **kw) self.__handle_request_response(response) return response def execute_get(self, *args, **kw): response = self.client.get(*args, **kw) self.__handle_request_response(response) return response def execute_delete(self, *args, **kw): response = self.client.delete(*args, **kw) self.__handle_request_response(response) return response def __handle_request_response(self, response: BaseResponse): if response.status_code == 500: app.logger.info(f"[INTERNAL SERVER ERROR]: {response.data}") if response.status_code == 400: app.logger.info(f"[BAD REQUEST]: {response.data}") if response.status_code == 403: app.logger.info(f"[FORBIDDEN]: {response.data}") if response.status_code == 401: app.logger.info(f"[UNAUTHORIZED]: {response.data}") if response.status_code == 422: app.logger.info(f"[Unprocessable Entity]: {response.data}") @staticmethod def load_fixture(fixture): FixtureLoader(models=models).import_as_sql(fixture) def setUp(self): app.config["SQLALCHEMY_ECHO"] = False es_log = logging.getLogger("elasticsearch") es_log.setLevel(logging.CRITICAL) self.tearDown() with self.app.app_context(): db.create_all() db.reflect() if self.fixture: self.load_fixture(self.fixture) def tearDown(self): with self.app.app_context(): # drop all views that depends on internal tables db.session.execute( """ DROP VIEW IF EXISTS user_labels_view; DROP VIEW IF EXISTS decibel_labels_view; DROP VIEW IF EXISTS projects_view; DROP VIEW IF EXISTS project_artists_view; DROP VIEW IF EXISTS project_campaigns_view; DROP VIEW IF EXISTS user_projects_view; DROP VIEW IF EXISTS campaigns_view; DROP VIEW IF EXISTS campaign_category_view; DROP VIEW IF EXISTS campaign_sub_category_view; DROP VIEW IF EXISTS campaign_objective_view; DROP VIEW IF EXISTS campaign_provider_view; DROP VIEW IF EXISTS campaign_platforms_view; DROP VIEW IF EXISTS linkfire_link_campaign_view; DROP VIEW IF EXISTS linkfire_link_project_view; """ ) db.session.flush() for model in models: if isinstance(model, Table): table_name = model.name else: table_name = model.__tablename__ db.session.execute( f""" TRUNCATE "{table_name}" RESTART IDENTITY CASCADE; """ ) db.session.execute( """ TRUNCATE projects, campaigns, project_artists, project_campaigns, user_projects, user_labels, decibel_labels, campaign_platforms, campaign_sub_category, campaign_provider, campaign_objective, campaign_category, linkfire_link_campaign, linkfire_link_project CASCADE; """ ) db.session.commit() db.session.remove() def soft_assert_equal(self, *arguments, **keywords): self.soft_assert(self.assertEqual, *arguments, **keywords) def mock_for_m2m_token() -> Mock: auth_mock = Mock() auth_mock.jwt.return_value = jwt auth_mock.jwt_decode.return_value = { "name": "Atlas Bridge", "aud": DECIBEL_M2M_ATLAS_BRIDGE_AUDIENCE } return auth_mock def mock_for_user( user_id: int, email: str, external_id: str, permissions: str = "access:mct", is_admin: bool = False, name: str ="User 1", labels: List[int] = [] ) -> Mock: auth_mock = Mock() auth_mock.user.return_value = User( id=user_id, email=email, name=email, external_id=external_id, updated_at=datetime.now(timezone.utc) ) auth_mock.jwt.return_value = jwt role = "superuser" if is_admin else "user" auth_mock.jwt_decode.return_value = { "decibel/role": [role], "decibel/labels": labels, "email": email, "name": name, "sub": external_id, # TODO: Auth0 legacy support. Remove after full Atlas integration "permissions": permissions, "http://private-api/user": {"roles": ["DecibelAdmin"] if is_admin else []}, } return auth_mock def get_file_path(fixture_file_name): return os.path.join(os.path.join(os.path.dirname(__file__)), fixture_file_name) mock = mock_for_user(1, "dev-marketing-user-1@example.com", "sme-dna|5cf0091d6c91d310fe6fcdc6")