Skip to content

Commit 521604d

Browse files
committed
wip
1 parent d66632f commit 521604d

File tree

4 files changed

+896
-0
lines changed

4 files changed

+896
-0
lines changed

TESTING_GUIDE.md

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# Testing run_udf_app - Guide for Beginners
2+
3+
This guide explains different approaches to testing the `run_udf_app` function in the SingleStoreDB Python SDK.
4+
5+
## Quick Start
6+
7+
Your sample code looks like this:
8+
```python
9+
from singlestoredb import apps
10+
from singlestoredb.functions import udf
11+
12+
@udf
13+
def hello() -> str:
14+
return "hello"
15+
16+
await apps.run_udf_app()
17+
```
18+
19+
## Testing Challenges
20+
21+
Testing `run_udf_app` is challenging because it:
22+
1. Starts a real web server (uvicorn)
23+
2. Reads environment variables
24+
3. Makes network calls
25+
4. Manages global state
26+
27+
## Testing Approaches
28+
29+
### 1. Mock Everything (Recommended for Unit Tests)
30+
- **File**: `test_apps.py`
31+
- **Best for**: Fast, reliable unit tests
32+
- **Mocks**: Server, environment, network calls
33+
- **Pros**: Fast, no external dependencies
34+
- **Cons**: Might miss integration issues
35+
36+
### 2. Test Error Cases First (Easiest to Start)
37+
- **File**: `test_apps_examples.py` (BeginnerTestExample)
38+
- **Best for**: Learning, catching configuration errors
39+
- **Focus**: Missing env vars, missing dependencies
40+
- **Pros**: Simple to write, catches real problems
41+
- **Cons**: Limited coverage
42+
43+
### 3. Pytest Style (Modern Approach)
44+
- **File**: `test_apps_pytest.py`
45+
- **Best for**: Clean, maintainable tests
46+
- **Features**: Fixtures, parameterized tests
47+
- **Pros**: Less boilerplate, better organization
48+
- **Cons**: Need to learn pytest
49+
50+
### 4. Integration Tests (Most Realistic)
51+
- **File**: `test_apps_examples.py` (InteractiveTestingExample)
52+
- **Best for**: End-to-end validation
53+
- **Tests**: Real UDF registration, actual function calls
54+
- **Pros**: Tests real behavior
55+
- **Cons**: Slower, more complex setup
56+
57+
## Running the Tests
58+
59+
```bash
60+
# Run all tests
61+
python -m pytest singlestoredb/tests/test_apps*.py
62+
63+
# Run specific test file
64+
python -m pytest singlestoredb/tests/test_apps.py
65+
66+
# Run with coverage
67+
python -m pytest --cov=singlestoredb.apps singlestoredb/tests/test_apps*.py
68+
69+
# Run specific test
70+
python -m pytest singlestoredb/tests/test_apps.py::TestRunUdfApp::test_run_udf_app_basic_success
71+
```
72+
73+
## Test Structure Explained
74+
75+
### Environment Variables Mock
76+
```python
77+
env_vars = {
78+
'SINGLESTOREDB_APP_LISTEN_PORT': '8080',
79+
'SINGLESTOREDB_NOVA_GATEWAY_ENABLED': 'true',
80+
# ... other required vars
81+
}
82+
```
83+
84+
### Server Mock
85+
```python
86+
mock_server = AsyncMock()
87+
mock_server.serve = AsyncMock()
88+
mock_server.wait_for_startup = AsyncMock()
89+
```
90+
91+
### Application Mock
92+
```python
93+
mock_app = MagicMock()
94+
mock_app.register_functions = MagicMock()
95+
mock_app.get_function_info.return_value = {'hello': {'signature': 'hello() -> str'}}
96+
```
97+
98+
## Common Test Patterns
99+
100+
### Testing Success Cases
101+
```python
102+
async def test_success():
103+
with patch.dict(os.environ, env_vars, clear=True):
104+
with patch('...AwaitableUvicornServer', return_value=mock_server):
105+
result = await run_udf_app()
106+
assert 'pythonudfs' in result.url
107+
```
108+
109+
### Testing Error Cases
110+
```python
111+
async def test_missing_env():
112+
with patch.dict(os.environ, {}, clear=True):
113+
with pytest.raises(RuntimeError, match="Missing"):
114+
await run_udf_app()
115+
```
116+
117+
### Testing with Real UDFs
118+
```python
119+
@udf
120+
def test_func() -> str:
121+
return "test"
122+
123+
async def test_with_udf():
124+
# ... setup mocks
125+
result = await run_udf_app()
126+
assert 'test_func' in result.functions
127+
```
128+
129+
## What to Test
130+
131+
### Essential Tests
132+
1.**Basic success case** - Function returns correct result
133+
2.**Missing environment variables** - Raises appropriate errors
134+
3.**Missing dependencies** - Handles missing uvicorn
135+
4.**Configuration parsing** - Reads env vars correctly
136+
137+
### Advanced Tests
138+
1.**Server lifecycle** - Properly shuts down existing servers
139+
2.**Interactive vs non-interactive** - Different behavior modes
140+
3.**UDF registration** - Functions are properly registered
141+
4.**Error handling** - Gateway disabled, port conflicts
142+
143+
### Performance Tests
144+
1.**Startup time** - How long does server take to start?
145+
2.**Memory usage** - Does it leak memory?
146+
3.**Concurrent calls** - Multiple simultaneous calls
147+
148+
## Tips for Beginners
149+
150+
1. **Start with error tests** - They're easier and catch real problems
151+
2. **Use pytest fixtures** - Reduces code duplication
152+
3. **Mock external dependencies** - Keep tests fast and reliable
153+
4. **Test one thing at a time** - Easier to debug when they fail
154+
5. **Use descriptive test names** - Explains what went wrong
155+
6. **Add comments** - Explain complex setup or assertions
156+
157+
## Debugging Failed Tests
158+
159+
### Common Issues
160+
- **Import errors**: Check that all required modules are available
161+
- **Environment variables**: Make sure all required vars are set in tests
162+
- **Async issues**: Use `@pytest.mark.asyncio` for async tests
163+
- **Mock problems**: Verify mock objects have the right methods
164+
165+
### Debugging Commands
166+
```bash
167+
# Run with verbose output
168+
python -m pytest -v singlestoredb/tests/test_apps.py
169+
170+
# Run single test with debug output
171+
python -m pytest -s singlestoredb/tests/test_apps.py::test_name
172+
173+
# See test coverage
174+
python -m pytest --cov-report=html --cov=singlestoredb.apps
175+
```
176+
177+
## Next Steps
178+
179+
1. **Pick an approach**: Start with error tests or basic mocking
180+
2. **Run existing tests**: Make sure your environment works
181+
3. **Write one test**: Start small with a simple case
182+
4. **Expand coverage**: Add more test cases gradually
183+
5. **Add integration tests**: Test with real UDFs when ready
184+
185+
## Resources
186+
187+
- [pytest documentation](https://docs.pytest.org/)
188+
- [unittest.mock documentation](https://docs.python.org/3/library/unittest.mock.html)
189+
- [AsyncMock documentation](https://docs.python.org/3/library/unittest.mock.html#unittest.mock.AsyncMock)

0 commit comments

Comments
 (0)