VibecoderMcSwaggins commited on
Commit
2bd9462
·
1 Parent(s): f66a862

feat: add smoke tests and fix Gradio 6.x compatibility

Browse files

- Add smoke tests for app initialization (catches config errors before deploy)
- Fix Gradio 6.x breaking changes:
- Remove `theme` param from gr.Blocks (removed in 6.x)
- Remove `type` param from gr.ChatInterface (removed in 6.x)
- Add typer to dev dependencies (required by Gradio CLI for smoke tests)

Smoke tests would have caught the previous deployment failures:
- Invalid examples format
- Gradio API changes

101 tests passing, 71% coverage

Files changed (4) hide show
  1. pyproject.toml +6 -0
  2. src/app.py +0 -2
  3. tests/unit/test_app_smoke.py +50 -0
  4. uv.lock +10 -0
pyproject.toml CHANGED
@@ -34,6 +34,7 @@ dev = [
34
  "pytest-cov>=5.0",
35
  "pytest-mock>=3.12",
36
  "respx>=0.21", # Mock httpx requests
 
37
 
38
  # Quality
39
  "ruff>=0.4.0",
@@ -131,5 +132,10 @@ exclude_lines = [
131
  "raise NotImplementedError",
132
  ]
133
 
 
 
 
 
 
134
  # Note: agent-framework-core is optional and installed locally for magentic mode
135
  # CI skips tests that require it via pytest.importorskip
 
34
  "pytest-cov>=5.0",
35
  "pytest-mock>=3.12",
36
  "respx>=0.21", # Mock httpx requests
37
+ "typer>=0.9.0", # Gradio CLI dependency for smoke tests
38
 
39
  # Quality
40
  "ruff>=0.4.0",
 
132
  "raise NotImplementedError",
133
  ]
134
 
135
+ [dependency-groups]
136
+ dev = [
137
+ "typer>=0.20.0",
138
+ ]
139
+
140
  # Note: agent-framework-core is optional and installed locally for magentic mode
141
  # CI skips tests that require it via pytest.importorskip
src/app.py CHANGED
@@ -129,7 +129,6 @@ def create_demo() -> Any:
129
  """
130
  with gr.Blocks(
131
  title="DeepCritical - Drug Repurposing Research Agent",
132
- theme=gr.themes.Soft(),
133
  ) as demo:
134
  gr.Markdown("""
135
  # 🧬 DeepCritical
@@ -147,7 +146,6 @@ def create_demo() -> Any:
147
  # Main chat interface (existing)
148
  gr.ChatInterface(
149
  fn=research_agent,
150
- type="messages", # type: ignore
151
  title="",
152
  examples=[
153
  ["What drugs could be repurposed for Alzheimer's disease?", "simple"],
 
129
  """
130
  with gr.Blocks(
131
  title="DeepCritical - Drug Repurposing Research Agent",
 
132
  ) as demo:
133
  gr.Markdown("""
134
  # 🧬 DeepCritical
 
146
  # Main chat interface (existing)
147
  gr.ChatInterface(
148
  fn=research_agent,
 
149
  title="",
150
  examples=[
151
  ["What drugs could be repurposed for Alzheimer's disease?", "simple"],
tests/unit/test_app_smoke.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Smoke tests for the Gradio app.
2
+
3
+ These tests verify the app can start without crashing.
4
+ They catch configuration errors like invalid Gradio parameters
5
+ that wouldn't be caught by unit tests.
6
+ """
7
+
8
+ import pytest
9
+
10
+
11
+ @pytest.mark.unit
12
+ class TestAppSmoke:
13
+ """Smoke tests for app initialization."""
14
+
15
+ def test_app_creates_demo(self) -> None:
16
+ """App should create Gradio demo without crashing.
17
+
18
+ This catches:
19
+ - Invalid Gradio component parameters
20
+ - Import errors
21
+ - Configuration issues
22
+ """
23
+ # Skip if gradio not fully installed (CI may not have all deps)
24
+ pytest.importorskip("gradio")
25
+ pytest.importorskip("typer") # Gradio CLI dependency
26
+
27
+ from src.app import create_demo
28
+
29
+ demo = create_demo()
30
+ assert demo is not None
31
+
32
+ def test_mcp_tools_importable(self) -> None:
33
+ """MCP tool functions should be importable.
34
+
35
+ Ensures the MCP server can expose these tools.
36
+ """
37
+ from src.mcp_tools import (
38
+ analyze_hypothesis,
39
+ search_all_sources,
40
+ search_biorxiv,
41
+ search_clinical_trials,
42
+ search_pubmed,
43
+ )
44
+
45
+ # Just verify they're callable
46
+ assert callable(search_pubmed)
47
+ assert callable(search_clinical_trials)
48
+ assert callable(search_biorxiv)
49
+ assert callable(search_all_sources)
50
+ assert callable(analyze_hypothesis)
uv.lock CHANGED
@@ -1087,6 +1087,7 @@ dev = [
1087
  { name = "pytest-sugar" },
1088
  { name = "respx" },
1089
  { name = "ruff" },
 
1090
  ]
1091
  embeddings = [
1092
  { name = "chromadb" },
@@ -1104,6 +1105,11 @@ modal = [
1104
  { name = "modal" },
1105
  ]
1106
 
 
 
 
 
 
1107
  [package.metadata]
1108
  requires-dist = [
1109
  { name = "agent-framework-core", marker = "extra == 'magentic'" },
@@ -1136,10 +1142,14 @@ requires-dist = [
1136
  { name = "sentence-transformers", marker = "extra == 'embeddings'", specifier = ">=2.2.0" },
1137
  { name = "structlog", specifier = ">=24.1" },
1138
  { name = "tenacity", specifier = ">=8.2" },
 
1139
  { name = "xmltodict", specifier = ">=0.13" },
1140
  ]
1141
  provides-extras = ["dev", "magentic", "embeddings", "modal"]
1142
 
 
 
 
1143
  [[package]]
1144
  name = "defusedxml"
1145
  version = "0.7.1"
 
1087
  { name = "pytest-sugar" },
1088
  { name = "respx" },
1089
  { name = "ruff" },
1090
+ { name = "typer" },
1091
  ]
1092
  embeddings = [
1093
  { name = "chromadb" },
 
1105
  { name = "modal" },
1106
  ]
1107
 
1108
+ [package.dev-dependencies]
1109
+ dev = [
1110
+ { name = "typer" },
1111
+ ]
1112
+
1113
  [package.metadata]
1114
  requires-dist = [
1115
  { name = "agent-framework-core", marker = "extra == 'magentic'" },
 
1142
  { name = "sentence-transformers", marker = "extra == 'embeddings'", specifier = ">=2.2.0" },
1143
  { name = "structlog", specifier = ">=24.1" },
1144
  { name = "tenacity", specifier = ">=8.2" },
1145
+ { name = "typer", marker = "extra == 'dev'", specifier = ">=0.9.0" },
1146
  { name = "xmltodict", specifier = ">=0.13" },
1147
  ]
1148
  provides-extras = ["dev", "magentic", "embeddings", "modal"]
1149
 
1150
+ [package.metadata.requires-dev]
1151
+ dev = [{ name = "typer", specifier = ">=0.20.0" }]
1152
+
1153
  [[package]]
1154
  name = "defusedxml"
1155
  version = "0.7.1"