From a8c0902e361b289e628c8508c42303acbb0de368 Mon Sep 17 00:00:00 2001 From: Carlos Vega <carlos.vega@lih.lu> Date: Thu, 29 Aug 2024 14:02:46 +0200 Subject: [PATCH] moved redcap test instance token and url to settings --- smash/smash/settings.py | 5 + smash/web/tests/functions.py | 308 ++++++++++++++++++++--------------- 2 files changed, 185 insertions(+), 128 deletions(-) diff --git a/smash/smash/settings.py b/smash/smash/settings.py index 53366991..5d3a28ae 100644 --- a/smash/smash/settings.py +++ b/smash/smash/settings.py @@ -23,6 +23,11 @@ PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ +# To run the unit tests we need a redcap instance. +# UL +REDCAP_TEST_API_TOKEN = "5DC21D45E3A2E068659F11046EA88734" +REDCAP_TEST_URL = "https://luxparktest.lcsb.uni.lu/redcap/" + COPYRIGHT_NOTE = "2024 Bioinformatics Core, Luxembourg Centre for Systems Biomedicine" DEBUG = True diff --git a/smash/web/tests/functions.py b/smash/web/tests/functions.py index 51d91ea3..60eddf74 100644 --- a/smash/web/tests/functions.py +++ b/smash/web/tests/functions.py @@ -6,14 +6,46 @@ from typing import Union from django.contrib.auth.models import Permission from django.contrib.auth import get_user_model from django.utils.timezone import make_aware, is_aware - -from web.models import Location, AppointmentType, StudySubject, Worker, Visit, Appointment, ConfigurationItem, \ - Language, ContactAttempt, FlyingTeam, Availability, Subject, Study, StudyColumns, StudyNotificationParameters, \ - VoucherType, VoucherTypePrice, Voucher, Room, Item, WorkerStudyRole, StudyRedCapColumns, EtlColumnMapping, \ - SubjectImportData, SubjectType -from web.models.constants import REDCAP_TOKEN_CONFIGURATION_TYPE, REDCAP_BASE_URL_CONFIGURATION_TYPE, \ - SEX_CHOICES_MALE, CONTACT_TYPES_PHONE, \ - MONDAY_AS_DAY_OF_WEEK, COUNTRY_AFGHANISTAN_ID, VOUCHER_STATUS_NEW, GLOBAL_STUDY_ID, DEFAULT_LOCALE_NAME +from django.conf import settings + +from web.models import ( + Location, + AppointmentType, + StudySubject, + Worker, + Visit, + Appointment, + ConfigurationItem, + Language, + ContactAttempt, + FlyingTeam, + Availability, + Subject, + Study, + StudyColumns, + StudyNotificationParameters, + VoucherType, + VoucherTypePrice, + Voucher, + Room, + Item, + WorkerStudyRole, + StudyRedCapColumns, + EtlColumnMapping, + SubjectImportData, + SubjectType, +) +from web.models.constants import ( + REDCAP_TOKEN_CONFIGURATION_TYPE, + REDCAP_BASE_URL_CONFIGURATION_TYPE, + SEX_CHOICES_MALE, + CONTACT_TYPES_PHONE, + MONDAY_AS_DAY_OF_WEEK, + COUNTRY_AFGHANISTAN_ID, + VOUCHER_STATUS_NEW, + GLOBAL_STUDY_ID, + DEFAULT_LOCALE_NAME, +) from web.models.worker_study_role import ROLE_CHOICES_DOCTOR, WORKER_VOUCHER_PARTNER from web.redcap_connector import RedcapSubject from web.views.notifications import get_today_midnight_date @@ -37,10 +69,12 @@ def create_voucher_type(): def create_voucher_type_price(): - return VoucherTypePrice.objects.create(voucher_type=create_voucher_type(), - price=12.34, - start_date=get_today_midnight_date(), - end_date=get_today_midnight_date()) + return VoucherTypePrice.objects.create( + voucher_type=create_voucher_type(), + price=12.34, + start_date=get_today_midnight_date(), + end_date=get_today_midnight_date(), + ) def create_empty_study_columns(): @@ -68,8 +102,9 @@ def create_study(name="test"): study_columns = StudyColumns.objects.create() notification_parameters = StudyNotificationParameters.objects.create() redcap_columns = StudyRedCapColumns.objects.create() - return Study.objects.create(name=name, columns=study_columns, notification_parameters=notification_parameters, - redcap_columns=redcap_columns) + return Study.objects.create( + name=name, columns=study_columns, notification_parameters=notification_parameters, redcap_columns=redcap_columns + ) TEST_ID_COUNTER = 0 @@ -90,14 +125,16 @@ def create_voucher(study_subject=None, partner=None, worker=None): if worker is None: worker = create_worker() number = str(get_test_id()) - return Voucher.objects.create(number=number, - study_subject=study_subject, - issue_date=get_today_midnight_date(), - expiry_date=get_today_midnight_date(), - voucher_type=create_voucher_type(), - usage_partner=partner, - issue_worker=worker, - status=VOUCHER_STATUS_NEW) + return Voucher.objects.create( + number=number, + study_subject=study_subject, + issue_date=get_today_midnight_date(), + expiry_date=get_today_midnight_date(), + voucher_type=create_voucher_type(), + usage_partner=partner, + issue_worker=worker, + status=VOUCHER_STATUS_NEW, + ) def create_empty_notification_parameters(): @@ -158,7 +195,7 @@ def get_test_study() -> Study: return create_study("test-study") -def create_appointment_type(code='C', default_duration=10, description='test'): +def create_appointment_type(code="C", default_duration=10, description="test"): return AppointmentType.objects.create( code=code, default_duration=default_duration, @@ -172,26 +209,25 @@ def create_contact_attempt(subject=None, worker=None): if worker is None: worker = create_worker() - return ContactAttempt.objects.create(subject=subject, - worker=worker, - type=CONTACT_TYPES_PHONE, - datetime_when=get_today_midnight_date(), - success=True, - comment="Successful contact attempt", - ) + return ContactAttempt.objects.create( + subject=subject, + worker=worker, + type=CONTACT_TYPES_PHONE, + datetime_when=get_today_midnight_date(), + success=True, + comment="Successful contact attempt", + ) def create_subject(): return Subject.objects.create( - first_name="Piotr", - last_name="Gawron", - sex=SEX_CHOICES_MALE, - country_id=COUNTRY_AFGHANISTAN_ID + first_name="Piotr", last_name="Gawron", sex=SEX_CHOICES_MALE, country_id=COUNTRY_AFGHANISTAN_ID ) -def create_study_subject(subject_id: int = 1, subject: Subject = None, nd_number: str = 'ND0001', - study: Study = None) -> StudySubject: +def create_study_subject( + subject_id: int = 1, subject: Subject = None, nd_number: str = "ND0001", study: Study = None +) -> StudySubject: if study is None: study = get_test_study() if subject is None: @@ -201,7 +237,7 @@ def create_study_subject(subject_id: int = 1, subject: Subject = None, nd_number type=get_control_subject_type(), screening_number="piotr's number" + str(subject_id), study=study, - subject=subject + subject=subject, ) if nd_number is not None: # null value in column "nd_number" violates not-null constraint study_subject.nd_number = nd_number @@ -211,11 +247,11 @@ def create_study_subject(subject_id: int = 1, subject: Subject = None, nd_number def get_control_subject_type() -> SubjectType: - return SubjectType.objects.filter(name='CONTROL').first() + return SubjectType.objects.filter(name="CONTROL").first() def get_patient_subject_type() -> SubjectType: - return SubjectType.objects.filter(name='PATIENT').first() + return SubjectType.objects.filter(name="PATIENT").first() def create_study_subject_with_multiple_screening_numbers(subject_id=1, subject=None, screening_number=None): @@ -223,13 +259,13 @@ def create_study_subject_with_multiple_screening_numbers(subject_id=1, subject=N subject = create_subject() if screening_number is None: - screening_number = f'E-00{subject_id}; L-00{subject_id}' + screening_number = f"E-00{subject_id}; L-00{subject_id}" return StudySubject.objects.create( default_location=get_test_location(), type=get_control_subject_type(), screening_number=screening_number, study=get_test_study(), - subject=subject + subject=subject, ) @@ -239,15 +275,12 @@ def create_red_cap_subject(): return result -def create_user(username: str = None, password: str = None, email: str = 'jacob@bla') -> get_user_model(): +def create_user(username: str = None, password: str = None, email: str = "jacob@bla") -> get_user_model(): if username is None: - username = 'piotr' + username = "piotr" if password is None: - password = 'top_secret' - user = get_user_model().objects.create_user( - username=username, - email=email, - password=password) + password = "top_secret" + user = get_user_model().objects.create_user(username=username, email=email, password=password) create_worker(user) return user @@ -262,49 +295,48 @@ def add_permissions_to_worker(worker, codenames): def create_worker(user=None, with_test_location=False): worker = Worker.objects.create( - first_name='piotr', + first_name="piotr", last_name="gawron", - email='jacob@bla.com', + email="jacob@bla.com", user=user, specialization="spec", unit="LCSB", - phone_number="0123456789" + phone_number="0123456789", ) if with_test_location: worker.locations.set([get_test_location()]) worker.save() - WorkerStudyRole.objects.create( - worker=worker, study_id=GLOBAL_STUDY_ID, name=ROLE_CHOICES_DOCTOR) + WorkerStudyRole.objects.create(worker=worker, study_id=GLOBAL_STUDY_ID, name=ROLE_CHOICES_DOCTOR) return worker def create_voucher_partner(): worker = Worker.objects.create( - first_name='piotr', + first_name="piotr", last_name="gawron", - email='jacob@bla.com', + email="jacob@bla.com", specialization="spec", unit="LCSB", - phone_number="0123456789" + phone_number="0123456789", ) - WorkerStudyRole.objects.create( - worker=worker, study_id=GLOBAL_STUDY_ID, name=WORKER_VOUCHER_PARTNER) + WorkerStudyRole.objects.create(worker=worker, study_id=GLOBAL_STUDY_ID, name=WORKER_VOUCHER_PARTNER) return worker def create_availability(worker=None, available_from=None, available_till=None, day_number=MONDAY_AS_DAY_OF_WEEK): if available_from is None: - available_from = '8:00' + available_from = "8:00" if available_till is None: - available_till = '18:00' + available_till = "18:00" if worker is None: worker = create_worker() - availability = Availability.objects.create(person=worker, - day_number=day_number, - available_from=available_from, - available_till=available_till, - ) + availability = Availability.objects.create( + person=worker, + day_number=day_number, + available_from=available_from, + available_till=available_till, + ) return availability @@ -315,10 +347,9 @@ def create_visit(subject: StudySubject = None, datetime_begin=None, datetime_end datetime_begin = get_today_midnight_date() + datetime.timedelta(days=-31) if datetime_end is None: datetime_end = get_today_midnight_date() + datetime.timedelta(days=31) - return Visit.objects.create(datetime_begin=datetime_begin, - datetime_end=datetime_end, - subject=subject, - is_finished=False) + return Visit.objects.create( + datetime_begin=datetime_begin, datetime_end=datetime_end, subject=subject, is_finished=False + ) def create_appointment(visit=None, when=None, length=30) -> Appointment: @@ -339,15 +370,14 @@ def create_appointment(visit=None, when=None, length=30) -> Appointment: length=length, location=get_test_location(), status=Appointment.APPOINTMENT_STATUS_SCHEDULED, - datetime_when=when_datetime) + datetime_when=when_datetime, + ) def create_appointment_without_visit(when=None, length=30): return Appointment.objects.create( - length=length, - location=get_test_location(), - status=Appointment.APPOINTMENT_STATUS_SCHEDULED, - datetime_when=when) + length=length, location=get_test_location(), status=Appointment.APPOINTMENT_STATUS_SCHEDULED, datetime_when=when + ) def create_configuration_item(): @@ -366,19 +396,24 @@ def create_flying_team(place=None): return result -def create_item(name='Test item', is_fixed=False, disposable=False): +def create_item(name="Test item", is_fixed=False, disposable=False): item = Item(name=name, is_fixed=is_fixed, disposable=disposable) item.save() return item -def create_room(owner='Test owner', city='Test city', - address='Test address', equipment=None, - floor=1, is_vehicle=False, room_number=1): +def create_room( + owner="Test owner", + city="Test city", + address="Test address", + equipment=None, + floor=1, + is_vehicle=False, + room_number=1, +): if equipment is None: equipment = [] - room = Room(owner=owner, city=city, address=address, - floor=floor, is_vehicle=is_vehicle, room_number=room_number) + room = Room(owner=owner, city=city, address=address, floor=floor, is_vehicle=is_vehicle, room_number=room_number) room.save() room.equipment.set(equipment) # Cannot be made in constructor/with single save room.save() @@ -392,14 +427,14 @@ def create_language(name="French", locale=DEFAULT_LOCALE_NAME) -> Language: def get_resource_path(filename): - return os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data', filename) + return os.path.join(os.path.dirname(os.path.realpath(__file__)), "data", filename) def format_form_field(value): if isinstance(value, datetime.date): - return value.strftime('%Y-%m-%d') + return value.strftime("%Y-%m-%d") elif isinstance(value, datetime.datetime): - return value.strftime('%Y-%m-%d %H:%M') + return value.strftime("%Y-%m-%d %H:%M") elif value is None: return "" else: @@ -409,14 +444,12 @@ def format_form_field(value): def prepare_test_redcap_connection(): Language.objects.create(name="Finnish").save() Language.objects.create(name="Italian").save() - token_item = ConfigurationItem.objects.filter( - type=REDCAP_TOKEN_CONFIGURATION_TYPE)[0] + token_item = ConfigurationItem.objects.filter(type=REDCAP_TOKEN_CONFIGURATION_TYPE)[0] # noinspection SpellCheckingInspection - token_item.value = "5DC21D45E3A2E068659F11046EA88734" + token_item.value = settings.REDCAP_TEST_API_TOKEN token_item.save() - url_item = ConfigurationItem.objects.filter( - type=REDCAP_BASE_URL_CONFIGURATION_TYPE)[0] - url_item.value = "https://luxparktest.lcsb.uni.lu/redcap/" + url_item = ConfigurationItem.objects.filter(type=REDCAP_BASE_URL_CONFIGURATION_TYPE)[0] + url_item.value = settings.REDCAP_TEST_URL url_item.save() @@ -427,49 +460,68 @@ def datetimeify_date(date: Union[datetime.date, str, bytes]) -> datetime.datetim else: return make_aware(date) if isinstance(date, bytes): # If it's bytes, then convert to string and carry on... - date = date.decode('utf8') + date = date.decode("utf8") if isinstance(date, str): # If it's string, convert to datetime with timezone support - return make_aware(datetime.datetime.strptime(date, '%Y-%m-%d')) + return make_aware(datetime.datetime.strptime(date, "%Y-%m-%d")) actual_type = str(type(date)) raise TypeError( - f"Date should be either a subclass of 'datetime.date', string or bytes! But is: {actual_type} instead") + f"Date should be either a subclass of 'datetime.date', string or bytes! But is: {actual_type} instead" + ) def create_tns_column_mapping(subject_import_data: SubjectImportData): - EtlColumnMapping.objects.create(etl_data=subject_import_data, - column_name="nd_number", - csv_column_name="donor_id", - table_name=StudySubject._meta.db_table) - EtlColumnMapping.objects.create(etl_data=subject_import_data, - column_name="comments", - csv_column_name="treatingphysician", - table_name=StudySubject._meta.db_table) - EtlColumnMapping.objects.create(etl_data=subject_import_data, - column_name="first_name", - csv_column_name="firstname", - table_name=Subject._meta.db_table) - EtlColumnMapping.objects.create(etl_data=subject_import_data, - column_name="first_name", - csv_column_name="sig_firstname", - table_name=Subject._meta.db_table) - EtlColumnMapping.objects.create(etl_data=subject_import_data, - column_name="last_name", - csv_column_name="lastname", - table_name=Subject._meta.db_table) - EtlColumnMapping.objects.create(etl_data=subject_import_data, - column_name="last_name", - csv_column_name="sig_lastname", - table_name=Subject._meta.db_table) - EtlColumnMapping.objects.create(etl_data=subject_import_data, - column_name="phone_number", - csv_column_name="phonenr", - table_name=Subject._meta.db_table) - EtlColumnMapping.objects.create(etl_data=subject_import_data, - column_name="date_born", - csv_column_name="dateofbirth", - table_name=Subject._meta.db_table) - EtlColumnMapping.objects.create(etl_data=subject_import_data, - column_name="next_of_kin_name", - csv_column_name="representative", - table_name=Subject._meta.db_table) + EtlColumnMapping.objects.create( + etl_data=subject_import_data, + column_name="nd_number", + csv_column_name="donor_id", + table_name=StudySubject._meta.db_table, + ) + EtlColumnMapping.objects.create( + etl_data=subject_import_data, + column_name="comments", + csv_column_name="treatingphysician", + table_name=StudySubject._meta.db_table, + ) + EtlColumnMapping.objects.create( + etl_data=subject_import_data, + column_name="first_name", + csv_column_name="firstname", + table_name=Subject._meta.db_table, + ) + EtlColumnMapping.objects.create( + etl_data=subject_import_data, + column_name="first_name", + csv_column_name="sig_firstname", + table_name=Subject._meta.db_table, + ) + EtlColumnMapping.objects.create( + etl_data=subject_import_data, + column_name="last_name", + csv_column_name="lastname", + table_name=Subject._meta.db_table, + ) + EtlColumnMapping.objects.create( + etl_data=subject_import_data, + column_name="last_name", + csv_column_name="sig_lastname", + table_name=Subject._meta.db_table, + ) + EtlColumnMapping.objects.create( + etl_data=subject_import_data, + column_name="phone_number", + csv_column_name="phonenr", + table_name=Subject._meta.db_table, + ) + EtlColumnMapping.objects.create( + etl_data=subject_import_data, + column_name="date_born", + csv_column_name="dateofbirth", + table_name=Subject._meta.db_table, + ) + EtlColumnMapping.objects.create( + etl_data=subject_import_data, + column_name="next_of_kin_name", + csv_column_name="representative", + table_name=Subject._meta.db_table, + ) -- GitLab