Spaces:
Runtime error
Runtime error
Upload folder using huggingface_hub
Browse files
backend/tests/test_database.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
import pytest_asyncio
|
| 3 |
+
import os
|
| 4 |
+
import sys
|
| 5 |
+
import aiosqlite
|
| 6 |
+
from collections import namedtuple
|
| 7 |
+
|
| 8 |
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 9 |
+
import database
|
| 10 |
+
|
| 11 |
+
# Mock settings to avoid real huggingface calls
|
| 12 |
+
database.settings.hf_token = None
|
| 13 |
+
database.DB_PATH = "test_patient_history.db"
|
| 14 |
+
|
| 15 |
+
@pytest_asyncio.fixture(autouse=True)
|
| 16 |
+
async def setup_teardown():
|
| 17 |
+
if os.path.exists(database.DB_PATH):
|
| 18 |
+
os.remove(database.DB_PATH)
|
| 19 |
+
await database.init_db()
|
| 20 |
+
yield
|
| 21 |
+
if os.path.exists(database.DB_PATH):
|
| 22 |
+
try:
|
| 23 |
+
os.remove(database.DB_PATH)
|
| 24 |
+
except PermissionError:
|
| 25 |
+
pass # Windows file lock fallback
|
| 26 |
+
|
| 27 |
+
@pytest.mark.asyncio
|
| 28 |
+
async def test_init_db():
|
| 29 |
+
assert os.path.exists(database.DB_PATH)
|
| 30 |
+
async with aiosqlite.connect(database.DB_PATH) as db:
|
| 31 |
+
cursor = await db.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='predictions'")
|
| 32 |
+
table = await cursor.fetchone()
|
| 33 |
+
assert table is not None
|
| 34 |
+
|
| 35 |
+
@pytest.mark.asyncio
|
| 36 |
+
async def test_log_and_get_history():
|
| 37 |
+
Data = namedtuple('Data', ['Heart_Rate', 'SpO2_Level', 'Systolic_BP', 'Diastolic_BP', 'Body_Temp'])
|
| 38 |
+
data = Data(80.0, 98.0, 120.0, 80.0, 37.0)
|
| 39 |
+
|
| 40 |
+
await database.log_prediction(data, "Normal", 0.95)
|
| 41 |
+
|
| 42 |
+
history = await database.get_history()
|
| 43 |
+
assert len(history) == 1
|
| 44 |
+
assert history[0]['heart_rate'] == 80.0
|
| 45 |
+
assert history[0]['prediction_label'] == "Normal"
|
| 46 |
+
assert history[0]['confidence'] == 0.95
|
| 47 |
+
|
| 48 |
+
@pytest.mark.asyncio
|
| 49 |
+
async def test_empty_history():
|
| 50 |
+
if os.path.exists(database.DB_PATH):
|
| 51 |
+
os.remove(database.DB_PATH)
|
| 52 |
+
history = await database.get_history()
|
| 53 |
+
assert history == []
|
backend/tests/test_ensemble.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
import numpy as np
|
| 3 |
+
import os
|
| 4 |
+
import sys
|
| 5 |
+
from unittest.mock import patch, MagicMock
|
| 6 |
+
|
| 7 |
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 8 |
+
from ensemble import EnsembleModel
|
| 9 |
+
|
| 10 |
+
@patch('joblib.load')
|
| 11 |
+
@patch('os.path.exists')
|
| 12 |
+
def test_ensemble_initialization(mock_exists, mock_load):
|
| 13 |
+
mock_exists.return_value = True
|
| 14 |
+
|
| 15 |
+
mock_model = MagicMock()
|
| 16 |
+
mock_load.return_value = mock_model
|
| 17 |
+
|
| 18 |
+
ensemble = EnsembleModel()
|
| 19 |
+
|
| 20 |
+
assert len(ensemble.models) == len(ensemble.model_names)
|
| 21 |
+
assert 'rf' in ensemble.models
|
| 22 |
+
assert 'logreg' in ensemble.models
|
| 23 |
+
|
| 24 |
+
@patch('joblib.load')
|
| 25 |
+
@patch('os.path.exists')
|
| 26 |
+
def test_ensemble_prediction(mock_exists, mock_load):
|
| 27 |
+
mock_exists.return_value = True
|
| 28 |
+
|
| 29 |
+
mock_model = MagicMock()
|
| 30 |
+
mock_model.predict_proba.return_value = np.array([[0.2, 0.8]])
|
| 31 |
+
|
| 32 |
+
mock_label_encoder = MagicMock()
|
| 33 |
+
mock_label_encoder.inverse_transform.side_effect = lambda x: [f"Class_{i}" for i in x]
|
| 34 |
+
|
| 35 |
+
def side_effect(path):
|
| 36 |
+
if 'label_encoder' in path:
|
| 37 |
+
return mock_label_encoder
|
| 38 |
+
return mock_model
|
| 39 |
+
|
| 40 |
+
mock_load.side_effect = side_effect
|
| 41 |
+
|
| 42 |
+
ensemble = EnsembleModel()
|
| 43 |
+
X_dummy = np.array([[1.0, 2.0, 3.0, 4.0, 5.0, 1.0]])
|
| 44 |
+
final_pred, confidence, individual_preds, class_probs, weights, individual_conf = ensemble.predict(X_dummy)
|
| 45 |
+
|
| 46 |
+
assert confidence == 0.8
|
| 47 |
+
assert final_pred == "Class_1"
|
| 48 |
+
assert "Class_0" in class_probs
|
| 49 |
+
assert class_probs["Class_1"] == 0.8
|
backend/tests/test_preprocessing.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
import os
|
| 5 |
+
import sys
|
| 6 |
+
|
| 7 |
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 8 |
+
from preprocessing import preprocess_data, resolve_model_dir
|
| 9 |
+
|
| 10 |
+
def test_resolve_model_dir():
|
| 11 |
+
md = resolve_model_dir()
|
| 12 |
+
assert md.endswith("model")
|
| 13 |
+
|
| 14 |
+
def test_preprocess_data_training():
|
| 15 |
+
df = pd.DataFrame({
|
| 16 |
+
'Heart Rate (bpm)': [80, 90, np.nan],
|
| 17 |
+
'SpO2 Level (%)': [98, 97, 95],
|
| 18 |
+
'Systolic Blood Pressure (mmHg)': [120, 125, 130],
|
| 19 |
+
'Diastolic Blood Pressure (mmHg)': [80, 85, 90],
|
| 20 |
+
'Body Temperature (°C)': [37.0, 37.2, 37.5],
|
| 21 |
+
'Predicted Disease': ['Normal', 'Asthma', 'Normal']
|
| 22 |
+
})
|
| 23 |
+
|
| 24 |
+
X, y = preprocess_data(df, is_training=True)
|
| 25 |
+
|
| 26 |
+
assert not X.isnull().values.any()
|
| 27 |
+
assert len(y) == 3
|
| 28 |
+
assert 'Risk_Severity' in X.columns
|
| 29 |
+
|
| 30 |
+
def test_preprocess_data_inference():
|
| 31 |
+
df = pd.DataFrame({
|
| 32 |
+
'Heart Rate (bpm)': [100],
|
| 33 |
+
'SpO2 Level (%)': [99],
|
| 34 |
+
'Systolic Blood Pressure (mmHg)': [120],
|
| 35 |
+
'Diastolic Blood Pressure (mmHg)': [80],
|
| 36 |
+
'Body Temperature (°C)': [37.0],
|
| 37 |
+
})
|
| 38 |
+
|
| 39 |
+
X, y = preprocess_data(df, is_training=False)
|
| 40 |
+
|
| 41 |
+
assert y is None
|
| 42 |
+
assert 'Risk_Severity' in X.columns
|
backend/tests/test_simulator.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
import asyncio
|
| 3 |
+
import sys
|
| 4 |
+
import os
|
| 5 |
+
|
| 6 |
+
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 7 |
+
from simulator import PatientDataSimulator
|
| 8 |
+
|
| 9 |
+
@pytest.mark.asyncio
|
| 10 |
+
async def test_simulator_initialization():
|
| 11 |
+
sim = PatientDataSimulator(initial_hr=80.0)
|
| 12 |
+
assert sim.hr == 80.0
|
| 13 |
+
assert sim.spo2 == 98.0
|
| 14 |
+
assert sim.sys_bp == 120.0
|
| 15 |
+
assert sim.dia_bp == 80.0
|
| 16 |
+
assert sim.temp == 37.0
|
| 17 |
+
|
| 18 |
+
@pytest.mark.asyncio
|
| 19 |
+
async def test_simulator_shift_state():
|
| 20 |
+
sim = PatientDataSimulator()
|
| 21 |
+
import random
|
| 22 |
+
random.seed(42)
|
| 23 |
+
sim.target_hr = 150.0
|
| 24 |
+
sim._step_physics()
|
| 25 |
+
assert sim.hr > 75.0
|
| 26 |
+
|
| 27 |
+
@pytest.mark.asyncio
|
| 28 |
+
async def test_simulator_run_yields_dict():
|
| 29 |
+
sim = PatientDataSimulator()
|
| 30 |
+
generator = sim.run()
|
| 31 |
+
data = await anext(generator)
|
| 32 |
+
assert isinstance(data, dict)
|
| 33 |
+
assert "Heart_Rate" in data
|
| 34 |
+
assert "SpO2_Level" in data
|
| 35 |
+
assert "Systolic_BP" in data
|
| 36 |
+
assert "Diastolic_BP" in data
|
| 37 |
+
assert "Body_Temp" in data
|