Skip to content

Commit dea5fdf

Browse files
authored
refactor(tests): split suites by execution level and speed up CI (#1609)
1 parent 542f2c9 commit dea5fdf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+3934
-2249
lines changed

.github/workflows/ci.yml

Lines changed: 132 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212

1313
concurrency:
1414
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
15-
cancel-in-progress: false
15+
cancel-in-progress: true
1616

1717
jobs:
1818
linting:
@@ -52,17 +52,14 @@ jobs:
5252
- name: Run mypy type checking
5353
run: uv run --frozen mypy langfuse --no-error-summary
5454

55-
ci:
55+
unit-tests:
5656
runs-on: blacksmith-4vcpu-ubuntu-2404
5757
timeout-minutes: 30
5858
env:
5959
LANGFUSE_BASE_URL: "http://localhost:3000"
60-
LANGFUSE_PUBLIC_KEY: "pk-lf-1234567890"
61-
LANGFUSE_SECRET_KEY: "sk-lf-1234567890"
62-
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
63-
# SERPAPI_API_KEY: ${{ secrets.SERPAPI_API_KEY }}
64-
HUGGINGFACEHUB_API_TOKEN: ${{ secrets.HUGGINGFACEHUB_API_TOKEN }}
65-
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
60+
LANGFUSE_PUBLIC_KEY: "pk-lf-test"
61+
LANGFUSE_SECRET_KEY: "sk-lf-test"
62+
OPENAI_API_KEY: "test-openai-key"
6663
strategy:
6764
fail-fast: false
6865
matrix:
@@ -73,56 +70,95 @@ jobs:
7370
- "3.13"
7471
- "3.14"
7572

76-
name: Test on Python version ${{ matrix.python-version }}
73+
name: Unit tests on Python ${{ matrix.python-version }}
7774
steps:
7875
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
79-
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5
76+
- name: Install uv and set Python version
77+
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8
8078
with:
81-
version: 10.33.0
79+
version: "0.11.2"
80+
python-version: ${{ matrix.python-version }}
81+
enable-cache: true
82+
83+
- name: Check Python version
84+
run: python --version
8285

83-
- name: Clone langfuse server
86+
- name: Install the project dependencies
87+
run: uv sync --locked
88+
89+
- name: Run the automated tests
8490
run: |
85-
git clone https://github.com/langfuse/langfuse.git ./langfuse-server && echo $(cd ./langfuse-server && git rev-parse HEAD)
91+
python --version
92+
uv run --frozen pytest -n auto --dist worksteal -s -v --log-cli-level=INFO tests/unit
8693
87-
- name: Setup node (for langfuse server)
88-
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
89-
with:
90-
node-version: 24
94+
e2e-tests:
95+
runs-on: ubuntu-latest
96+
timeout-minutes: 30
97+
strategy:
98+
fail-fast: false
99+
matrix:
100+
include:
101+
- suite: e2e
102+
job_name: E2E shard 1 tests on Python 3.13
103+
shard_name: shard-1
104+
shard_index: 0
105+
shard_count: 2
106+
- suite: e2e
107+
job_name: E2E shard 2 tests on Python 3.13
108+
shard_name: shard-2
109+
shard_index: 1
110+
shard_count: 2
111+
- suite: live_provider
112+
job_name: E2E live-provider tests on Python 3.13
113+
shard_name: live-provider
114+
env:
115+
LANGFUSE_BASE_URL: "http://localhost:3000"
116+
LANGFUSE_PUBLIC_KEY: "pk-lf-1234567890"
117+
LANGFUSE_SECRET_KEY: "sk-lf-1234567890"
118+
LANGFUSE_INIT_ORG_ID: "0c6c96f4-0ca0-4f16-92a8-6dd7d7c6a501"
119+
LANGFUSE_INIT_ORG_NAME: "SDK Test Org"
120+
LANGFUSE_INIT_PROJECT_ID: "7a88fb47-b4e2-43b8-a06c-a5ce950dc53a"
121+
LANGFUSE_INIT_PROJECT_NAME: "SDK Test Project"
122+
LANGFUSE_INIT_PROJECT_PUBLIC_KEY: "pk-lf-1234567890"
123+
LANGFUSE_INIT_PROJECT_SECRET_KEY: "sk-lf-1234567890"
124+
LANGFUSE_INIT_USER_EMAIL: "sdk-tests@langfuse.local"
125+
LANGFUSE_INIT_USER_NAME: "SDK Tests"
126+
LANGFUSE_INIT_USER_PASSWORD: "langfuse-ci-password"
127+
LANGFUSE_E2E_READ_TIMEOUT_SECONDS: "60"
128+
LANGFUSE_E2E_READ_INTERVAL_SECONDS: "0.5"
129+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
130+
# SERPAPI_API_KEY: ${{ secrets.SERPAPI_API_KEY }}
131+
HUGGINGFACEHUB_API_TOKEN: ${{ secrets.HUGGINGFACEHUB_API_TOKEN }}
132+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
91133

92-
- name: Cache langfuse server dependencies
93-
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
134+
name: ${{ matrix.job_name }}
135+
steps:
136+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
137+
- name: Install uv and set Python version
138+
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8
94139
with:
95-
path: ./langfuse-server/node_modules
96-
key: langfuse-serve-${{ hashFiles('langfuse-server/pnpm-lock.yaml') }}
97-
restore-keys: |
98-
langfuse-serve-
140+
version: "0.11.2"
141+
python-version: "3.13"
142+
enable-cache: true
143+
- name: Install the project dependencies
144+
run: uv sync --locked
145+
- name: Check uv Python version
146+
run: uv run --frozen python --version
147+
- name: Prepare langfuse server compose
148+
run: |
149+
mkdir -p ./langfuse-server
150+
LANGFUSE_SERVER_SHA="$(git ls-remote https://github.com/langfuse/langfuse.git HEAD | cut -f1)"
151+
curl -fsSL "https://raw.githubusercontent.com/langfuse/langfuse/${LANGFUSE_SERVER_SHA}/docker-compose.yml" \
152+
-o ./langfuse-server/docker-compose.yml
153+
echo "${LANGFUSE_SERVER_SHA}"
99154
100155
- name: Run langfuse server
101156
run: |
102157
cd ./langfuse-server
103158
104-
echo "::group::Run langfuse server"
105-
TELEMETRY_ENABLED=false docker compose up -d postgres
106-
echo "::endgroup::"
107-
108-
echo "::group::Logs from langfuse server"
109-
TELEMETRY_ENABLED=false docker compose logs
110-
echo "::endgroup::"
111-
112-
echo "::group::Install dependencies (necessary to run seeder)"
113-
pnpm i
114-
echo "::endgroup::"
115-
116-
echo "::group::Seed db"
117-
cp .env.dev.example .env
118-
pnpm run db:migrate
119-
pnpm run db:seed
120-
echo "::endgroup::"
121-
rm -rf .env
122-
123-
echo "::group::Run server"
124-
159+
echo "::group::Start langfuse server"
125160
TELEMETRY_ENABLED=false \
161+
NEXT_PUBLIC_LANGFUSE_RUN_NEXT_INIT=true \
126162
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT=http://localhost:9090 \
127163
LANGFUSE_INGESTION_QUEUE_DELAY_MS=10 \
128164
LANGFUSE_INGESTION_CLICKHOUSE_WRITE_INTERVAL_MS=10 \
@@ -131,51 +167,81 @@ jobs:
131167
LANGFUSE_ENABLE_EVENTS_TABLE_V2_APIS=true \
132168
LANGFUSE_ENABLE_EVENTS_TABLE_OBSERVATIONS=true \
133169
docker compose up -d
134-
135170
echo "::endgroup::"
136171
137-
# Add this step to check the health of the container
138172
- name: Health check for langfuse server
139173
run: |
140174
echo "Checking if the langfuse server is up..."
141175
retry_count=0
142-
max_retries=10
143-
until curl --output /dev/null --silent --head --fail http://localhost:3000/api/public/health
176+
max_retries=20
177+
until curl --output /dev/null --silent --head --fail http://localhost:3000/api/public/health && \
178+
uv run --frozen python -c "from langfuse import Langfuse; client = Langfuse(); project_id = client._get_project_id(); assert project_id == '7a88fb47-b4e2-43b8-a06c-a5ce950dc53a', project_id; print(project_id)"
144179
do
145180
retry_count=`expr $retry_count + 1`
146181
echo "Attempt $retry_count of $max_retries..."
147182
if [ $retry_count -ge $max_retries ]; then
148183
echo "Langfuse server did not respond in time. Printing logs..."
149-
docker logs langfuse-server-langfuse-web-1
184+
(cd ./langfuse-server && docker compose ps)
185+
(cd ./langfuse-server && docker compose logs langfuse-web langfuse-worker)
150186
echo "Failing the step..."
151187
exit 1
152188
fi
153189
sleep 5
154190
done
155191
echo "Langfuse server is up and running!"
156192
157-
- name: Install uv and set Python version
158-
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8
159-
with:
160-
version: "0.11.2"
161-
python-version: ${{ matrix.python-version }}
162-
enable-cache: true
163-
164-
- name: Check Python version
165-
run: python --version
166-
167-
- name: Install the project dependencies
168-
run: uv sync --locked
169-
170-
- name: Run the automated tests
193+
- name: Select e2e shard files
194+
if: ${{ matrix.suite == 'e2e' }}
171195
run: |
172-
python --version
173-
uv run --frozen pytest -n auto --dist loadfile -s -v --log-cli-level=INFO
196+
uv run --frozen python scripts/select_e2e_shard.py \
197+
--shard-index ${{ matrix.shard_index }} \
198+
--shard-count ${{ matrix.shard_count }} \
199+
--json
200+
uv run --frozen python scripts/select_e2e_shard.py \
201+
--shard-index ${{ matrix.shard_index }} \
202+
--shard-count ${{ matrix.shard_count }} \
203+
> "$RUNNER_TEMP/e2e-shard-files.txt"
204+
cat "$RUNNER_TEMP/e2e-shard-files.txt"
205+
206+
- name: Run the parallel end-to-end tests
207+
if: ${{ matrix.suite == 'e2e' }}
208+
run: |
209+
uv run --frozen python --version
210+
mapfile -t e2e_files < "$RUNNER_TEMP/e2e-shard-files.txt"
211+
set +e
212+
uv run --frozen pytest -n 4 --dist worksteal -s -v --log-cli-level=INFO "${e2e_files[@]}" -m "not serial_e2e"
213+
status=$?
214+
set -e
215+
if [ "$status" -eq 5 ]; then
216+
echo "No parallel e2e tests selected for this shard."
217+
elif [ "$status" -ne 0 ]; then
218+
exit "$status"
219+
fi
220+
221+
- name: Run serial end-to-end tests
222+
if: ${{ matrix.suite == 'e2e' }}
223+
run: |
224+
mapfile -t e2e_files < "$RUNNER_TEMP/e2e-shard-files.txt"
225+
set +e
226+
uv run --frozen pytest -s -v --log-cli-level=INFO "${e2e_files[@]}" -m "serial_e2e"
227+
status=$?
228+
set -e
229+
if [ "$status" -eq 5 ]; then
230+
echo "No serial e2e tests selected for this shard."
231+
elif [ "$status" -ne 0 ]; then
232+
exit "$status"
233+
fi
234+
235+
- name: Run live-provider tests
236+
if: ${{ matrix.suite == 'live_provider' }}
237+
run: |
238+
uv run --frozen python --version
239+
uv run --frozen pytest -n 4 --dist worksteal -s -v --log-cli-level=INFO tests/live_provider -m "live_provider"
174240
175241
all-tests-passed:
176242
# This allows us to have a branch protection rule for tests and deploys with matrix
177243
runs-on: blacksmith-2vcpu-ubuntu-2404
178-
needs: [ci, linting, type-checking]
244+
needs: [unit-tests, e2e-tests, linting, type-checking]
179245
if: always()
180246
steps:
181247
- name: Successful deploy

0 commit comments

Comments
 (0)