Skip to content

Commit f1ccdcc

Browse files
committed
testing-farm-sse-bridge: Add Testing Farm SSE bridge service
The Testing Farm SSE bridge provides a Server-Sent Events interface for Testing Farm requests. It consists of a FastAPI application that polls Testing Farm and streams updates to connected clients. Testing Farm's REST API currently provides no way to notify new clients of state changes for existing requests, which requires the clients to poll. This commit addresses that by adding a bridge service that efficiently polls Testing Farm on behalf of the client and streams updates via SSE. This provides a stop gap until Testing Farm gains the feature itself.
1 parent 5bdf6cb commit f1ccdcc

File tree

9 files changed

+708
-0
lines changed

9 files changed

+708
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
__pycache__/
2+
*.py[cod]
3+
*.egg-info/
4+
.dist-info/
5+
.eggs/
6+
.git/
7+
.gitignore
8+
venv/
9+
.venv/
10+
.env
11+
.cache/
12+
.pytest_cache/
13+
dist/
14+
build/
15+
.coverage
16+
junit.xml
17+
Containerfile

testing-farm-sse-bridge/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Red Hat, Inc.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

testing-farm-sse-bridge/README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Testing Farm SSE Bridge
2+
3+
A FastAPI-based SSE bridge for Testing Farm requests.
4+
5+
## Overview
6+
7+
The Testing Farm SSE Bridge provides a Server-Sent Events (SSE) interface for Testing Farm requests, making it easier to integrate Testing Farm with other services.
8+
9+
## Features
10+
11+
- SSE endpoint for Testing Farm requests
12+
- FastAPI-based REST API
13+
- Configurable via environment variables
14+
- Container-ready with multi-stage builds
15+
16+
## Quick Start
17+
18+
### Using Podman Compose
19+
20+
1. Copy the environment template:
21+
```bash
22+
cp templates/testing-farm-sse-bridge.env .secrets/testing-farm-sse-bridge.env
23+
```
24+
25+
2. Edit `.secrets/testing-farm-sse-bridge.env` and set your Testing Farm token.
26+
27+
3. Start the service:
28+
```bash
29+
podman compose up testing-farm-sse-bridge
30+
```
31+
32+
### Manual Setup
33+
34+
1. Install dependencies:
35+
```bash
36+
pip install .
37+
```
38+
39+
2. Set required environment variables:
40+
```bash
41+
export TESTING_FARM_API_TOKEN=your-token-here
42+
export TESTING_FARM_API_URL=https://api.testing-farm.io
43+
```
44+
45+
3. Run the service:
46+
```bash
47+
testing-farm-sse-bridge --host=0.0.0.0 --port=10000
48+
```
49+
50+
## Container Images
51+
52+
Pre-built container images are available on Quay.io:
53+
54+
```bash
55+
podman pull quay.io/jotnar/testing-farm-sse-bridge:latest
56+
```
57+
58+
### Building Locally
59+
60+
Build the production image:
61+
```bash
62+
podman build -t testing-farm-sse-bridge:latest -f Containerfile .
63+
```
64+
65+
Build with debug tools:
66+
```bash
67+
podman build -t testing-farm-sse-bridge:debug -f Containerfile --target debug .
68+
```
69+
70+
## Configuration
71+
72+
The service is configured via environment variables:
73+
74+
| Variable | Description | Default |
75+
|----------|-------------|---------|
76+
| HOST | Server host | 0.0.0.0 |
77+
| PORT | Server port | 10000 |
78+
| LOG_LEVEL | Logging level (debug, info, warning, error) | info |
79+
| TESTING_FARM_API_URL | Testing Farm API URL | https://api.testing-farm.io |
80+
| TESTING_FARM_API_TOKEN | Testing Farm API token | Required |
81+
| TESTING_FARM_POLL_INTERVAL | Poll interval in seconds | 5.0 |
82+
| TESTING_FARM_TIMEOUT | Request timeout in seconds | 30.0 |
83+
84+
## Development
85+
86+
Install development dependencies:
87+
```bash
88+
pip install ".[dev]"
89+
```
90+
91+
Run tests:
92+
```bash
93+
pytest
94+
```
95+
96+
## License
97+
98+
MIT License - see LICENSE file for details.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[project]
2+
name = "testing-farm-sse-bridge"
3+
version = "0.1.0"
4+
description = "FastAPI-based SSE bridge for Testing Farm requests"
5+
readme = "README.md"
6+
requires-python = ">=3.10"
7+
license = { text = "MIT" }
8+
authors = [
9+
{ name = "Ray Strode", email = "[email protected]" },
10+
]
11+
keywords = ["testing-farm", "sse", "fastapi", "uvicorn"]
12+
classifiers = [
13+
"Programming Language :: Python :: 3",
14+
"Programming Language :: Python :: 3 :: Only",
15+
"Programming Language :: Python :: 3.10",
16+
"Programming Language :: Python :: 3.11",
17+
"Programming Language :: Python :: 3.12",
18+
"License :: OSI Approved :: MIT License",
19+
"Framework :: FastAPI",
20+
"Topic :: Internet :: WWW/HTTP",
21+
]
22+
23+
# Runtime dependencies
24+
dependencies = [
25+
"fastapi>=0.111.0",
26+
"httpx>=0.27.0",
27+
"uvicorn>=0.30.0",
28+
]
29+
30+
[build-system]
31+
requires = ["hatchling>=1.25.0"]
32+
build-backend = "hatchling.build"
33+
34+
[project.scripts]
35+
# CLI entrypoint: `testing-farm-sse-bridge` → launches uvicorn
36+
"testing-farm-sse-bridge" = "testing_farm_sse_bridge.__main__:main"
37+
# Convenience scripts for container build and run
38+
"container-build" = "testing_farm_sse_bridge.build_container:main"
39+
"container" = "testing_farm_sse_bridge.run_container:main"
40+
41+
42+
[tool.hatch.build]
43+
include = [
44+
"testing_farm_sse_bridge",
45+
"README.md",
46+
"LICENSE",
47+
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "0.1.0"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import argparse
2+
import os
3+
from typing import Optional
4+
5+
import uvicorn
6+
7+
8+
def main(argv: Optional[list[str]] = None) -> None:
9+
parser = argparse.ArgumentParser(description="Run Testing Farm SSE Bridge (FastAPI/uvicorn)")
10+
parser.add_argument("--host", default=os.environ.get("HOST", "0.0.0.0"), help="Bind host")
11+
parser.add_argument("--port", type=int, default=int(os.environ.get("PORT", "10000")), help="Bind port")
12+
parser.add_argument(
13+
"--log-level", default=os.environ.get("LOG_LEVEL", "info"), choices=["critical", "error", "warning", "info", "debug", "trace"],
14+
)
15+
args = parser.parse_args(argv)
16+
17+
uvicorn.run(
18+
"testing_farm_sse_bridge.app:app",
19+
host=args.host,
20+
port=args.port,
21+
log_level=args.log_level,
22+
reload=False,
23+
workers=1,
24+
proxy_headers=True,
25+
)
26+
27+
28+
if __name__ == "__main__":
29+
main()

0 commit comments

Comments
 (0)