forked from globaldothealth/InsightBoard
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add system tests * Add chromedriver to ci action * Check if insightboard config exists in system tests * Add sleep before asserts in system tests * Refine system tests * Wait for InsightBoard to start in system tests * Migrate from gunicorn to waitress for cross-platform compatibility * Wait for InsightBoard to start before opening webbrowser / running system tests * Take screenshot if system test fails * Resolve temporary file access permissions (Windows)
- Loading branch information
1 parent
0c3598f
commit c5741d0
Showing
25 changed files
with
737 additions
and
149 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,38 @@ | ||
import os | ||
import time | ||
import socket | ||
import subprocess | ||
import webbrowser | ||
from .app import app # noqa: F401 | ||
|
||
from .version import __version__ # noqa: F401 | ||
|
||
INSIGHTBOARD_PORT = os.getenv("INSIGHTBOARD_PORT", 8050) | ||
INSIGHTBOARD_TIMEOUT = os.getenv("INSIGHTBOARD_TIMEOUT", 30) | ||
|
||
def main(debug=False): | ||
port = 8050 | ||
|
||
def launch_app() -> subprocess.Popen: | ||
cmd = [ | ||
"gunicorn", | ||
"waitress-serve", | ||
f"--listen=0.0.0.0:{INSIGHTBOARD_PORT}", | ||
"InsightBoard.app:server", | ||
*["--bind", f"0.0.0.0:{port}"], | ||
] | ||
process = subprocess.Popen(cmd) | ||
webbrowser.open(f"http://127.0.0.1:{port}") | ||
return subprocess.Popen(cmd) | ||
|
||
|
||
def wait_for_server(port=INSIGHTBOARD_PORT, timeout=INSIGHTBOARD_TIMEOUT) -> bool: | ||
start_time = time.time() | ||
while time.time() - start_time < timeout: | ||
try: | ||
with socket.create_connection(("127.0.0.1", port), timeout=1): | ||
return True # Server is up | ||
except (OSError, ConnectionRefusedError): | ||
time.sleep(1) | ||
raise TimeoutError(f"Server did not start within {timeout} seconds") | ||
|
||
|
||
def main(debug=False): | ||
process = launch_app() | ||
wait_for_server(INSIGHTBOARD_PORT, INSIGHTBOARD_TIMEOUT) | ||
webbrowser.open(f"http://127.0.0.1:{INSIGHTBOARD_PORT}") | ||
process.wait() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
chromedriver |
Empty file.
Empty file.
21 changes: 21 additions & 0 deletions
21
tests/system/InsightBoard/projects/sample_project/data/sample_data_source1.csv
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
CaseNumber,PersonAge,Sex,City,OnsetDate,ReportedSymptoms,HealthOutcome,VaxStatus,RecoveryDays,PreexistingConditions | ||
001,34,Male,New York,08/10/2023,"fever, cough, headache",recovered,yes,10,None | ||
002,27,F,L.A.,09/08/2023,"fever, cough, fatigue",recovered,No,15,Athma | ||
003,55,Female,Chicago,10/08/2023,"short breath, fatigue",Deceased,no,N/A,Diabeties | ||
004,40,M,Houston,11/08/2023,"fever, cough",Recovered,Yes,12,High BP | ||
005,62,Other,Miami,12/08/2023,"fatigue, muscle pain, fever",Died,no,N/A,None | ||
006,18,F,Seattle,"13/08/2023","fever, cough",Recov,Partial,8,None | ||
007,70,M,Atlanta,14/08/2023,"fever, shortness of breath",Dead,None,N/A,Lung issue | ||
008,50,Female,SF,15/08/2023,"fever, headache",Recovered,yes,11,HBP | ||
009,44,Female,Boston,16/08/2023,"fatigue, muscle ache",recovered,Yes,13,None | ||
010,29,Male,Denver,17/08/2023,"fever, coughing",recovered,Partial,9,None | ||
011,23,Male,LV,18/08/2023,"fatigue, muscle pain",Recov,none,14,None | ||
012,37,F,Dallas,19/08/2023,"fever, cough, fatigue",Recovd,YES,10,None | ||
013,60,Male,NewYork,20/08/2023,"fever, short breath",Died,NO,N/A,Heart problems | ||
014,47,O,S.D.,21/08/2023,"fever, coughing",recovered,yes,12,None | ||
015,33,Female,Chicago,22/08/2023,"fever, headache",recovered,no,11,None | ||
016,25,Male,Philly,23/08/2023,"fatigue, muscle pain",Recov,Partial,8,None | ||
017,71,F,Detroit,24/08/2023,"short breath",Dead,No,N/A,Kidney Disease | ||
018,38,F,Houston,25/08/2023,"fever, coughing",recovered,yes,9,None | ||
019,55,Male,L.A.,26/08/2023,"fever, fatigue",Recov,None,15,Asthma | ||
020,65,Female,NYC,27/08/2023,"short breath",Dead,No,N/A,Diabetes |
27 changes: 27 additions & 0 deletions
27
tests/system/InsightBoard/projects/sample_project/parsers/adtl-source1.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from tempfile import NamedTemporaryFile | ||
import pandas as pd | ||
from pathlib import Path | ||
import adtl | ||
from InsightBoard.parsers import parse_adtl | ||
|
||
SPECIFICATION_FILE = Path("adtl") / "source1.toml" | ||
TABLE_NAME = "linelist" | ||
|
||
|
||
def parse(df: pd.DataFrame) -> list[dict]: | ||
spec_file = Path(__file__).parent / SPECIFICATION_FILE | ||
return parse_adtl(df, spec_file, [TABLE_NAME]) | ||
|
||
|
||
def test_parse(): | ||
print("Test: Parse") | ||
data_file = Path(__file__).parent.parent / "data" / "sample_data_source1.csv" | ||
orig_df = pd.read_csv(data_file) | ||
rtn = parse(orig_df) | ||
df = rtn[0]["data"] | ||
assert isinstance(df, pd.DataFrame) | ||
print("Test: Parse - Passed") | ||
|
||
|
||
if __name__ == "__main__": | ||
test_parse() |
75 changes: 75 additions & 0 deletions
75
tests/system/InsightBoard/projects/sample_project/parsers/adtl/source1.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
[adtl] | ||
name = "source1" | ||
description = "Parses the sample dataset" | ||
defaultDateFormat = "%d/%m/%Y" | ||
|
||
[adtl.tables] | ||
linelist = { kind = "oneToOne", schema = "../../schemas/linelist.schema.json" } | ||
|
||
[linelist] | ||
|
||
[linelist."Case ID"] | ||
field = "CaseNumber" | ||
|
||
[linelist.Age] | ||
field = "PersonAge" | ||
|
||
[linelist.Gender] | ||
field = "Sex" | ||
ignoreMissingKey = true | ||
|
||
[linelist.Gender.values] | ||
"Male" = "Male" | ||
"Female" = "Female" | ||
"Other" = "Other" | ||
"M" = "Male" | ||
"F" = "Female" | ||
"O" = "Other" | ||
|
||
[linelist.Location] | ||
field = "City" | ||
|
||
[linelist."Date of Onset"] | ||
field = "OnsetDate" | ||
ignoreMissingKey = true | ||
|
||
[linelist.Symptoms] | ||
field = "ReportedSymptoms" | ||
|
||
[linelist.Outcome] | ||
field = "HealthOutcome" | ||
ignoreMissingKey = true | ||
|
||
[linelist.Outcome.values] | ||
"Recovered" = "Recovered" | ||
"Deceased" = "Deceased" | ||
"Death" = "Deceased" | ||
"Dead" = "Deceased" | ||
"Died" = "Deceased" | ||
"recovered" = "Recovered" | ||
"Recov" = "Recovered" | ||
|
||
[linelist."Vaccination Status"] | ||
field = "VaxStatus" | ||
ignoreMissingKey = true | ||
|
||
[linelist."Vaccination Status".values] | ||
"yes" = "Yes" | ||
"no" = "No" | ||
"Yes" = "Yes" | ||
"No" = "No" | ||
"YES" = "Yes" | ||
"NO" = "No" | ||
"none" = "No" | ||
"Partial" = "Partial" | ||
"Vaccinated" = "Yes" | ||
"Not Vaccinated" = "No" | ||
"V" = "Yes" | ||
"N" = "No" | ||
"null" = "Unknown" | ||
|
||
[linelist."Days to Recovery"] | ||
field = "RecoveryDays" | ||
|
||
[linelist."Underlying Conditions"] | ||
field = "PreexistingConditions" |
Empty file.
58 changes: 58 additions & 0 deletions
58
tests/system/InsightBoard/projects/sample_project/schemas/linelist.schema.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
{ | ||
"$schema": "http://json-schema.org/draft-07/schema#", | ||
"type": "object", | ||
"properties": { | ||
"Case ID": { | ||
"type": "integer", | ||
"description": "Unique identifier for each case", | ||
"PrimaryKey": true | ||
}, | ||
"Age": { | ||
"type": "integer", | ||
"description": "Age of the patient", | ||
"minimum": 0 | ||
}, | ||
"Gender": { | ||
"type": "string", | ||
"description": "Gender of the patient", | ||
"enum": ["Male", "Female", "Other"] | ||
}, | ||
"Location": { | ||
"type": "string", | ||
"description": "City or region where the case was reported" | ||
}, | ||
"Date of Onset": { | ||
"type": "string", | ||
"format": "date", | ||
"description": "Date when symptoms first appeared" | ||
}, | ||
"Symptoms": { | ||
"type": ["array", "null"], | ||
"description": "List of symptoms exhibited by the patient", | ||
"items": { | ||
"type": "string" | ||
} | ||
}, | ||
"Outcome": { | ||
"type": ["string", "null"], | ||
"description": "Final outcome for the patient (recovered or deceased)", | ||
"enum": ["Recovered", "Deceased", null] | ||
}, | ||
"Vaccination Status": { | ||
"type": ["string", "null"], | ||
"description": "Vaccination status of the patient", | ||
"enum": ["Yes", "No", "Partial", "Unknown"] | ||
}, | ||
"Days to Recovery": { | ||
"type": ["integer", "null"], | ||
"description": "Number of days to recover, null for deceased cases" | ||
}, | ||
"Underlying Conditions": { | ||
"type": ["string", "null"], | ||
"description": "Pre-existing health conditions of the patient", | ||
"enum": ["None", "Asthma", "Diabetes", "Hypertension", "Heart Disease", "Chronic Lung Disease", "Chronic Kidney Disease", null] | ||
} | ||
}, | ||
"required": ["Case ID", "Age", "Gender", "Location", "Date of Onset"], | ||
"additionalProperties": false | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import time | ||
import pytest | ||
from pathlib import Path | ||
from utils import ( | ||
driver, | ||
page_upload, | ||
chromedriver_present, | ||
save_screenshot, | ||
) | ||
|
||
|
||
@pytest.mark.skipif(not chromedriver_present, reason="chromedriver not present") | ||
def test_insightboard(driver): | ||
upload = page_upload(driver) | ||
upload.clear_data() | ||
try: | ||
upload.select_parser("adtl-source1") | ||
data_file = ( | ||
Path(__file__).parent | ||
/ "InsightBoard" | ||
/ "projects" | ||
/ "sample_project" | ||
/ "data" | ||
/ "sample_data_source1.csv" | ||
) | ||
assert data_file.exists() | ||
upload.select_data_file(str(data_file)) | ||
upload.parse() | ||
time.sleep(1) | ||
upload.check_DataTable_row_count(20) | ||
# Only show validation errors: Check that the validated rows are hidden | ||
upload.toggle_only_show_validation_errors() | ||
time.sleep(1) | ||
upload.check_DataTable_row_count(10) | ||
# Revert to showing all rows | ||
upload.toggle_only_show_validation_errors() | ||
time.sleep(1) | ||
upload.check_DataTable_row_count(20) | ||
except Exception as e: | ||
screenshot_path = save_screenshot(driver) | ||
raise Exception(f"Screenshot saved to: {screenshot_path}") from e |
Oops, something went wrong.