Skip to content

Commit 9c66df6

Browse files
authored
RHOAIENG-26843: tests(trustyai): add trustyai compatibility smoke test for JupyterLab images with scikit-learn (opendatahub-io#1187)
1 parent 25728a0 commit 9c66df6

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

tests/containers/conftest.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,16 @@ def jupyterlab_datascience_image(jupyterlab_image: Image) -> Image:
162162
return jupyterlab_image
163163

164164

165+
@pytest.fixture(scope="function")
166+
def jupyterlab_trustyai_image(jupyterlab_image: Image) -> Image:
167+
if "-trustyai-" not in jupyterlab_image.labels["name"]:
168+
pytest.skip(
169+
f"Image {jupyterlab_image.name} is not trustyai image because it does not have '-trustyai-' in {jupyterlab_image.labels['name']=}'"
170+
)
171+
172+
return jupyterlab_image
173+
174+
165175
@pytest.fixture(scope="function")
166176
def rstudio_image(image: str) -> Image:
167177
image_metadata = skip_if_not_workbench_image(image)
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
from __future__ import annotations
2+
3+
import pathlib
4+
import tempfile
5+
6+
import allure
7+
8+
from tests.containers import conftest, docker_utils
9+
from tests.containers.workbenches.workbench_image_test import WorkbenchContainer
10+
11+
12+
class TestJupyterLabDatascienceImage:
13+
"""Tests for JupyterLab Workbench images in this repository that have trustyai."""
14+
15+
APP_ROOT_HOME = "/opt/app-root/src"
16+
17+
@allure.issue("RHOAIENG-26843")
18+
@allure.description("Check that basic trustyai+scikit-learn functionality is working.")
19+
def test_trustyai_with_sklearn_smoke(self, jupyterlab_trustyai_image: conftest.Image) -> None:
20+
container = WorkbenchContainer(image=jupyterlab_trustyai_image.name, user=4321, group_add=[0])
21+
# language=Python
22+
test_script_content = '''
23+
#!/usr/bin/env python3
24+
"""
25+
Standalone smoke test for TrustyAI-scikit-learn compatibility.
26+
Can be run directly in the trustyai notebook environment.
27+
"""
28+
29+
import sys
30+
import traceback
31+
32+
33+
def test_sklearn_trustyai_compatibility():
34+
"""Test basic compatibility between TrustyAI and scikit-learn."""
35+
try:
36+
import numpy as np
37+
import pandas as pd
38+
import sklearn
39+
from sklearn.ensemble import RandomForestClassifier
40+
from sklearn.model_selection import train_test_split
41+
import trustyai
42+
from trustyai.metrics.fairness.group import statistical_parity_difference
43+
from trustyai.model import output
44+
45+
print(f"✓ Successfully imported all required packages")
46+
print(f" - scikit-learn version: {sklearn.__version__}")
47+
print(f" - trustyai version: {trustyai.__version__}")
48+
49+
# Verify scikit-learn version is approximately 1.5.x
50+
sklearn_version = sklearn.__version__
51+
if not sklearn_version.startswith('1.5'):
52+
print(f"⚠️ Warning: Expected scikit-learn ~1.5.x, got {sklearn_version}")
53+
54+
# Test basic sklearn functionality
55+
print("✓ Testing basic scikit-learn functionality...")
56+
np.random.seed(42)
57+
X = np.random.randn(100, 3)
58+
y = (X[:, 0] + X[:, 1] > 0).astype(int)
59+
60+
model = RandomForestClassifier(n_estimators=5, random_state=42)
61+
model.fit(X, y)
62+
predictions = model.predict(X[:10])
63+
print(f" - Model trained and made predictions: {predictions[:5]}")
64+
65+
# Test TrustyAI functionality
66+
print("✓ Testing TrustyAI functionality...")
67+
protected_attr = np.random.choice([0, 1], size=len(X), p=[0.6, 0.4])
68+
69+
df = pd.DataFrame(X, columns=['f1', 'f2', 'f3'])
70+
df['prediction'] = model.predict(X)
71+
df['protected'] = protected_attr
72+
favorable = output("income", dtype="number", value=1)
73+
74+
# https://github.com/trustyai-explainability/trustyai-explainability-python-examples/blob/main/examples/GroupFairnessMetrics.ipynb
75+
spd = statistical_parity_difference(
76+
privileged=df[df.protected == 0],
77+
unprivileged=df[df.protected == 1],
78+
favorable=[favorable],
79+
)
80+
print(f" - Statistical Parity Difference calculated: {spd:.3f}")
81+
82+
# Test TrustyAI output creation
83+
outputs = [output(name=f"pred_{i}", dtype="number", value=float(pred))
84+
for i, pred in enumerate(predictions[:3])]
85+
print(f" - Created {len(outputs)} TrustyAI output instances")
86+
87+
print("🎉 All compatibility tests passed!")
88+
return True
89+
90+
except Exception as e:
91+
print(f"❌ Compatibility test failed: {e}")
92+
traceback.print_exc()
93+
return False
94+
95+
96+
if __name__ == "__main__":
97+
success = test_sklearn_trustyai_compatibility()
98+
sys.exit(0 if success else 1)
99+
'''
100+
test_script_name = "test_trustyai.py"
101+
try:
102+
container.start(wait_for_readiness=False)
103+
with tempfile.TemporaryDirectory() as tmpdir:
104+
tmpdir_path = pathlib.Path(tmpdir)
105+
script_path = tmpdir_path / test_script_name
106+
script_path.write_text(test_script_content)
107+
docker_utils.container_cp(
108+
container.get_wrapped_container(),
109+
src=str(script_path),
110+
dst=self.APP_ROOT_HOME,
111+
)
112+
113+
script_container_path = f"{self.APP_ROOT_HOME}/{test_script_name}"
114+
exit_code, output = container.exec(["python", script_container_path])
115+
output_str = output.decode()
116+
117+
print(f"Script output:\n{output_str}")
118+
119+
assert exit_code == 0, f"Script execution failed with exit code {exit_code}. Output:\n{output_str}"
120+
assert "🎉 All compatibility tests passed!" in output_str
121+
assert "- Statistical Parity Difference calculated: 1.000" in output_str
122+
123+
finally:
124+
docker_utils.NotebookContainer(container).stop(timeout=0)

0 commit comments

Comments
 (0)