Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: ♻️ change GQL custom test class to use transation #361

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions core/jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from django.apps import apps
from django.utils import timezone
from django.dispatch import receiver
from core.models import InteractiveUser
import logging
import uuid
from datetime import datetime
Expand Down Expand Up @@ -93,10 +94,8 @@ def get_jwt_key(encode=True, context=None, payload=None):

def extract_private_key_from_payload(payload):
# Get user private key from payload. This covers the refresh token mutation
from core.models import User

if "username" in payload:
return User.objects.get(username=payload["username"]).private_key
if "username" in payload:
return InteractiveUser.objects.get(login_name=payload["username"]).private_key


def extract_private_key_from_context(context):
Expand Down
65 changes: 64 additions & 1 deletion core/models/openimis_graphql_test_case.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,92 @@
import json
from django.conf import settings
from graphene_django.utils.testing import GraphQLTestCase
from django.core.management import call_command
from django.apps import apps
from django.db import transaction, connection

from django.test import TransactionTestCase
from simple_history.models import HistoricalChanges
import uuid
import logging
from graphene import Schema
from graphene.test import Client
import datetime
import time
from core.models import ObjectMutation, MutationLog


logger = logging.getLogger(__name__)

MODEL_NOT_TO_FLUSH = [
'gender',
'role',
'roleright',
'profession',
'familytype',
'location',
'healthfacility',
'permission'

]
TABLE_TO_FLUSH = ['tblLogins', 'tblHealthStatus']

class openIMISGraphQLTestCase(GraphQLTestCase):
class openIMISGraphQLTestCase(TransactionTestCase):
GRAPHQL_URL = f"/{settings.SITE_ROOT()}graphql"
GRAPHQL_SCHEMA = True

def query(self, query, **kwargs):
"""
Execute a GraphQL query using the client.
"""
return GraphQLTestCase.query.__call__(self, query, **kwargs)

class BaseTestContext:
def __init__(self, user):
self.user = user
# client = None
def setUp(self):
# cls.client=Client(cls.schema)
GraphQLTestCase.setUp.__call__(self)
super().setUp()
Comment on lines +42 to +51
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that this implementation is inheriting from one class and reaching out to another class that is meant to be inherited from with __call__ multiple times, creates a code smell.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that the only way I found in python to call an external with another context, inheritance don't work because GraphQLTestCase inherite for TestCase, which inherite from TransactionTestCase .... yes it smell




def _fixture_teardown(self):
with transaction.atomic(), connection.cursor() as cursor:
for table_name in TABLE_TO_FLUSH:
cursor.execute(f'TRUNCATE TABLE "{table_name}"')

for app in apps.get_app_configs():
models_dict = app.models
# Print model names and their classes
for model_name, model_class in models_dict.items():
if (
model_name.lower() not in MODEL_NOT_TO_FLUSH
and model_class._meta.db_table
and not 'View' in model_class._meta.db_table
and not model_class._meta.swapped
):
savepoint = transaction.savepoint()
try:
cursor.execute(f'TRUNCATE TABLE "{model_class._meta.db_table}"')
except Exception as e:
# Roll back to the savepoint (only this operation will be undone)
transaction.savepoint_rollback(savepoint)
Comment on lines +55 to +75
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like a hack. Can we run tests without --keepdb but instead setup db in a custom class SeededTestRunner(DiscoverRunner) and inside setup_databases setup MODEL_NOT_TO_FLUSH using fixtures?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes but we will need a proper way to init the db, we are working on that with solution building



@classmethod
def setUpClass(cls):
# cls.client=Client(cls.schema)
super(openIMISGraphQLTestCase, cls).setUpClass()


def assertResponseNoErrors(self, resp, **kwargs):
return GraphQLTestCase.assertResponseNoErrors(self, resp, kwargs)

def assertResponseHasErrors(self, resp, **kwargs):
return GraphQLTestCase.assertResponseHasErrors(self, resp, kwargs)

def get_mutation_result(self, mutation_uuid, token, internal=False):
content = None
while True:
Expand Down
3 changes: 3 additions & 0 deletions core/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ class Meta:


class InteractiveUser(VersionedModel):

USERNAME_FIELD = 'login_name'

id = models.AutoField(db_column="UserID", primary_key=True)
uuid = models.CharField(db_column="UserUUID", max_length=36, default=uuid.uuid4, unique=True)
language = models.ForeignKey(Language, models.DO_NOTHING, db_column="LanguageID")
Expand Down
9 changes: 9 additions & 0 deletions core/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,16 @@ def create_test_interactive_user(username='TestInteractiveTest', password="S\\:\
}
)


if not user:
user = User.objects.filter(
username=username,
).first()
if user:
user.i_user = i_user
user.save()

if not user:
user = User.objects.create(
username=username,
i_user=i_user,
Expand Down
Loading