44 pull_request :
55 branches : [ main ]
66
7-
87jobs :
98 test :
10- runs-on : macos-15
9+ name : Test on ${{ matrix.os }}
10+ runs-on : ${{ matrix.os }}
1111 strategy :
12+ fail-fast : false
1213 matrix :
13- python-version : ['3.11']
14+ include :
15+ - os : ubuntu-latest
16+ python-version : ' 3.11'
17+ # Install gpu (sglang) and dev dependencies for Linux
18+ extras : ' gpu, dev'
19+ - os : macos-latest
20+ python-version : ' 3.11'
21+ # Install mac (mlx) and dev dependencies for macOS
22+ extras : ' mac, dev'
1423
1524 steps :
25+ - name : Free Disk Space (Ubuntu)
26+ if : runner.os == 'Linux'
27+ uses : jlumbroso/free-disk-space@v1.3.1
28+ with :
29+ tool-cache : false
30+ android : true
31+ dotnet : true
32+ haskell : true
33+ large-packages : true
34+ docker-images : true
35+ swap-storage : false
36+
1637 - name : Checkout code
1738 uses : actions/checkout@v4
1839
@@ -23,16 +44,18 @@ jobs:
2344 filters : |
2445 src:
2546 - 'src/**'
47+ - 'tests/**'
48+ - 'pyproject.toml'
2649
2750 - name : Set up Python ${{ matrix.python-version }}
2851 if : steps.changes.outputs.src == 'true'
29- uses : actions/setup-python@v4
52+ uses : actions/setup-python@v5
3053 with :
3154 python-version : ${{ matrix.python-version }}
3255
3356 - name : Cache pip dependencies
3457 if : steps.changes.outputs.src == 'true'
35- uses : actions/cache@v3
58+ uses : actions/cache@v4
3659 with :
3760 path : ~/.cache/pip
3861 key : ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }}
@@ -44,32 +67,65 @@ jobs:
4467 if : steps.changes.outputs.src == 'true'
4568 run : |
4669 python -m pip install --upgrade pip
47- pip install -e '.[mac, dev]'
70+ # Install extras dependencies based on matrix variable
71+ pip install -e ".[${{ matrix.extras }}]"
4872
49- - name : Run tests
50- if : steps.changes.outputs.src == 'true'
51- run : pytest tests/ -v --cov=src/parallax --cov-report=xml
73+ - name : Run Unit Tests (macOS only)
74+ if : steps.changes.outputs.src == 'true' && runner.os == 'macOS'
75+ shell : bash
76+ run : |
77+ pytest tests/ -v --cov=src/parallax --cov-report=xml
5278
5379 - name : Upload coverage to Codecov
54- if : steps.changes.outputs.src == 'true'
55- uses : codecov/codecov-action@v3
80+ if : steps.changes.outputs.src == 'true' && runner.os == 'macOS'
81+ uses : codecov/codecov-action@v4
5682 with :
5783 file : ./coverage.xml
5884 fail_ci_if_error : false
85+ token : ${{ secrets.CODECOV_TOKEN }}
5986
60- - name : Run E2E tests
61- if : steps.changes.outputs.src == 'true'
87+ - name : Run E2E tests (macOS only)
88+ if : steps.changes.outputs.src == 'true' && runner.os == 'macOS'
89+ shell : bash
6290 run : |
91+ # Start the server
6392 python src/parallax/launch.py \
64- --model-path Qwen/Qwen3-0.6B-MLX-bf16 \
93+ --model-path Qwen/Qwen3-0.6B \
6594 --max-num-tokens-per-batch 16384 \
6695 --kv-block-size 1024 \
6796 --max-batch-size 128 \
6897 --start-layer 0 \
6998 --end-layer 28 &
7099 PID=$!
71- sleep 60
72- curl --location 'http://localhost:3000/v1/chat/completions' --header 'Content-Type: application/json' --data '{
100+
101+ echo "Waiting for server to start..."
102+ # Poll to check if the port is ready (wait up to 60 seconds)
103+ for i in {1..30}; do
104+ # If curl succeeds (200) or returns 405 (Method Not Allowed), the port is open
105+ if curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/v1/chat/completions | grep -qE "200|400|405"; then
106+ echo "Server is up!"
107+ break
108+ fi
109+
110+ # Check if the process is still alive
111+ if ! kill -0 $PID 2>/dev/null; then
112+ echo "Server process died prematurely"
113+ exit 1
114+ fi
115+
116+ if [ $i -eq 30 ]; then
117+ echo "Server failed to start within 60 seconds"
118+ kill $PID 2>/dev/null
119+ exit 1
120+ fi
121+ sleep 2
122+ done
123+
124+ echo "Sending test request..."
125+ # Capture the response
126+ RESPONSE=$(curl --fail --silent --show-error --location 'http://localhost:3000/v1/chat/completions' \
127+ --header 'Content-Type: application/json' \
128+ --data '{
73129 "messages": [
74130 {
75131 "role": "user",
@@ -82,6 +138,19 @@ jobs:
82138 "sampling_params": {
83139 "top_k": 3
84140 }
85- }'
141+ }')
142+
143+ echo "Response received:"
144+ echo "$RESPONSE"
145+
146+ # Check if the response contains "Paris" (case-insensitive)
147+ if echo "$RESPONSE" | grep -iq "Paris"; then
148+ echo "Test passed: Response contains 'Paris'"
149+ else
150+ echo "Test failed: Response does not contain 'Paris'"
151+ kill $PID 2>/dev/null || true
152+ exit 1
153+ fi
154+
155+ # Clean up process
86156 kill $PID 2>/dev/null || true
87- wait $PID 2>/dev/null || echo -e "\nE2E test completed after 60 seconds"
0 commit comments