Skip to content

Commit 7452a9f

Browse files
authored
Merge branch 'tensorzero:main' into main
2 parents 37fd8c7 + 4ebc537 commit 7452a9f

File tree

205 files changed

+14690
-1732
lines changed

Some content is hidden

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

205 files changed

+14690
-1732
lines changed

.cargo/config.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,11 @@ build-e2e = "build --bin gateway --features e2e_tests"
4444
run-e2e = "run --bin gateway --features e2e_tests -- --config-file tensorzero-core/tests/e2e/tensorzero.toml"
4545
watch-e2e = "watch -x run-e2e"
4646

47-
# Export Typescript bindings for TensorZero
48-
tsbuild = ["test", "export_bindings", "-p", "tensorzero-core"]
47+
tsbuild = [
48+
"test",
49+
"export_bindings",
50+
"-p",
51+
"tensorzero-core",
52+
"-p",
53+
"tensorzero",
54+
] # Export Typescript bindings for TensorZero

.github/workflows/general.yml

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,13 +350,17 @@ jobs:
350350
run: find . -name "Chart.yaml" -exec dirname {} \; | xargs -I {} helm lint {}
351351

352352
clickhouse-tests:
353+
name: "ClickHouse tests (replicated: ${{ matrix.replicated }}) (version: ${{ matrix.clickhouse_version.tag }})"
354+
353355
# We don't run many tests here, so use a normal runner with Github Actions caching
354356
# to avoid unnecessarily using Namespace credits (it should still always finish before
355357
# the main 'validate' job)
356-
runs-on: ubuntu-latest
358+
runs-on: ${{ matrix.replicated && 'namespace-profile-tensorzero-large-cache-volume' || 'ubuntu-latest' }}
357359
continue-on-error: ${{ matrix.clickhouse_version.allow_failure }}
358360
strategy:
359361
matrix:
362+
# Only include replicated: true when running in merge queue
363+
replicated: ${{ github.event_name == 'merge_group' && fromJSON('[true, false]') || fromJSON('[false]') }}
360364
clickhouse_version:
361365
- tag: "24.12-alpine"
362366
prefix: "24.12"
@@ -390,6 +394,10 @@ jobs:
390394
with:
391395
tool: cargo-nextest
392396

397+
- name: Set ClickHouse replicated cluster name
398+
if: matrix.replicated == true
399+
run: echo "TENSORZERO_CLICKHOUSE_CLUSTER_NAME=tensorzero_e2e_tests_cluster" >> $GITHUB_ENV
400+
393401
- name: Install uv
394402
run: curl -LsSf https://astral.sh/uv/0.6.17/install.sh | sh
395403

@@ -400,9 +408,14 @@ jobs:
400408
run: |
401409
echo "TENSORZERO_CLICKHOUSE_URL=http://chuser:chpassword@localhost:8123/tensorzero_e2e_tests" >> $GITHUB_ENV
402410
403-
- name: Launch ClickHouse container for E2E tests
411+
- name: Launch non-replicated ClickHouse container for E2E tests
412+
if: matrix.replicated == false
404413
run: TENSORZERO_CLICKHOUSE_VERSION=${{ matrix.clickhouse_version.tag }} docker compose -f tensorzero-core/tests/e2e/docker-compose.yml up clickhouse --wait
405414

415+
- name: Launch replicated ClickHouse container for E2E tests
416+
if: matrix.replicated == true
417+
run: TENSORZERO_CLICKHOUSE_VERSION=${{ matrix.clickhouse_version.tag }} docker compose -f tensorzero-core/tests/e2e/docker-compose.replicated.yml up clickhouse-01 clickhouse-02 clickhouse-03 --wait
418+
406419
# Make an HTTP request to ClickHouse and check that the version matches '${{ matrix.clickhouse_version }}'
407420
- name: Check ClickHouse version
408421
run: |
@@ -415,8 +428,27 @@ jobs:
415428
- name: Build the gateway for E2E tests
416429
run: cargo build-e2e
417430

418-
- name: Launch the gateway for E2E tests
431+
- name: Launch the gateway for E2E tests (not configured for replication)
432+
if: matrix.replicated == false
433+
run: |
434+
cargo run-e2e > e2e_logs.txt 2>&1 &
435+
count=0
436+
max_attempts=10
437+
while ! curl -s -f http://localhost:3000/health >/dev/null 2>&1; do
438+
echo "Waiting for gateway to be healthy..."
439+
sleep 1
440+
count=$((count + 1))
441+
if [ $count -ge $max_attempts ]; then
442+
echo "Gateway failed to become healthy after $max_attempts attempts"
443+
exit 1
444+
fi
445+
done
446+
echo "GATEWAY_PID=$!" >> $GITHUB_ENV
447+
448+
- name: Launch the gateway for E2E tests (configured for replication)
449+
if: matrix.replicated == true
419450
run: |
451+
cargo run-e2e --run-migrations-only &&
420452
cargo run-e2e > e2e_logs.txt 2>&1 &
421453
count=0
422454
max_attempts=10
@@ -434,6 +466,46 @@ jobs:
434466
- name: Test (Rust)
435467
run: cargo test-e2e-no-creds
436468

469+
- name: Print docker compose logs (replicated)
470+
if: always() && matrix.replicated == true
471+
run: |
472+
TENSORZERO_CLICKHOUSE_VERSION=${{ matrix.clickhouse_version.tag }} docker compose -f tensorzero-core/tests/e2e/docker-compose.replicated.yml logs -t
473+
474+
- name: Print ClickHouse error logs (replicated)
475+
if: always() && matrix.replicated == true
476+
run: |
477+
echo "Error logs for ClickHouse 01:"
478+
docker exec e2e-clickhouse-01-1 cat /var/log/clickhouse-server/clickhouse-server.err.log
479+
echo "Error logs for ClickHouse 02:"
480+
docker exec e2e-clickhouse-02-1 cat /var/log/clickhouse-server/clickhouse-server.err.log
481+
echo "Error logs for ClickHouse 03:"
482+
docker exec e2e-clickhouse-03-1 cat /var/log/clickhouse-server/clickhouse-server.err.log
483+
484+
- name: Print ClickHouse trace logs (replicated)
485+
if: always() && matrix.replicated == true
486+
run: |
487+
echo "Trace logs for ClickHouse 01:"
488+
docker exec e2e-clickhouse-01-1 cat /var/log/clickhouse-server/clickhouse-server.log
489+
echo "Trace logs for ClickHouse 02:"
490+
docker exec e2e-clickhouse-02-1 cat /var/log/clickhouse-server/clickhouse-server.log
491+
echo "Trace logs for ClickHouse 03:"
492+
docker exec e2e-clickhouse-03-1 cat /var/log/clickhouse-server/clickhouse-server.log
493+
494+
- name: Print container health checks (replicated)
495+
if: always() && matrix.replicated == true
496+
run: |
497+
echo "Health check for ClickHouse 01:"
498+
docker inspect --format "{{json .State.Health }}" $(docker compose -f tensorzero-core/tests/e2e/docker-compose.replicated.yml ps -q clickhouse-01) | jq
499+
echo "Health check for ClickHouse 02:"
500+
docker inspect --format "{{json .State.Health }}" $(docker compose -f tensorzero-core/tests/e2e/docker-compose.replicated.yml ps -q clickhouse-02) | jq
501+
echo "Health check for ClickHouse 03:"
502+
docker inspect --format "{{json .State.Health }}" $(docker compose -f tensorzero-core/tests/e2e/docker-compose.replicated.yml ps -q clickhouse-03) | jq
503+
504+
- name: Print docker compose logs (non-replicated)
505+
if: always() && matrix.replicated == false
506+
run: |
507+
TENSORZERO_CLICKHOUSE_VERSION=${{ matrix.clickhouse_version.tag }} docker compose -f tensorzero-core/tests/e2e/docker-compose.yml logs -t
508+
437509
- name: Print e2e logs
438510
if: always()
439511
run: cat e2e_logs.txt

.github/workflows/merge-queue.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,22 @@ jobs:
264264
docker compose -f examples/production-deployment/docker-compose.yml down
265265
docker compose -f tensorzero-core/tests/e2e/docker-compose.yml down
266266
267+
# Test that the ui e2e tests still pass after we regenerate the model inference cache
268+
ui-tests-e2e-regen-model-inference-cache:
269+
uses: ./.github/workflows/ui-tests-e2e-model-inference-cache.yml
270+
with:
271+
regen_cache: true
272+
secrets:
273+
S3_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
274+
S3_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
275+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
276+
FIREWORKS_ACCOUNT_ID: ${{ secrets.FIREWORKS_ACCOUNT_ID }}
277+
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
278+
267279
# See 'ci/README.md' at the repository root for more details.
268280
check-all-live-tests-passed:
269281
if: always()
270-
needs: [check-production-docker-container, live-tests, batch-tests]
282+
needs: [check-production-docker-container, ui-tests-e2e-regen-model-inference-cache, live-tests, batch-tests]
271283
runs-on: ubuntu-latest
272284
steps:
273285
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
name: UI E2E tests with model inference cache
2+
3+
on:
4+
workflow_call:
5+
secrets:
6+
S3_ACCESS_KEY_ID:
7+
required: true
8+
S3_SECRET_ACCESS_KEY:
9+
required: true
10+
OPENAI_API_KEY:
11+
required: false
12+
FIREWORKS_ACCOUNT_ID:
13+
required: false
14+
FIREWORKS_API_KEY:
15+
required: false
16+
inputs:
17+
regen_cache:
18+
required: true
19+
type: boolean
20+
21+
jobs:
22+
ui-tests-e2e:
23+
runs-on: namespace-profile-tensorzero-8x16
24+
# We currently only run this job when we have secrets available, since we need to use an S3 object_store
25+
# In the future, we might want to fix this so that it can run in PR CI for external (forked) PRs
26+
# For now, it just runs in the merge queue and on prs from the main repo
27+
if: ${{ (github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]') || github.event_name == 'merge_group' }}
28+
29+
steps:
30+
# TODO - investigate why using the Namespace checkout action causes
31+
# 'tensorzero_core::built_info::GIT_COMMIT_HASH_SHORT' to be `None`
32+
- name: Check out the repo
33+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
34+
35+
- name: Setup Node
36+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
37+
with:
38+
node-version: "22.9.0"
39+
40+
- name: Setup `pnpm`
41+
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda
42+
43+
- name: Install `pnpm` dependencies
44+
run: pnpm install --frozen-lockfile
45+
46+
- name: Setup Playwright
47+
run: pnpm --filter=tensorzero-ui exec playwright install --with-deps chromium
48+
49+
- name: Cache `s3-fixtures`
50+
uses: namespacelabs/nscloud-cache-action@2f50e7d0f70475e6f59a55ba0f05eec9108e77cc
51+
with:
52+
path: |
53+
./ui/fixtures/s3-fixtures
54+
55+
# When we're regenerating the model inference cache, don't download the container images
56+
# The images will get built by `regenerate-model-inference-cache.sh`
57+
- name: Download container images
58+
if: inputs.regen_cache == false
59+
uses: namespace-actions/download-artifact@5c070f7d7ebdc47682b04aa736c76e46ff5f6e1e
60+
with:
61+
pattern: build-*-container
62+
merge-multiple: true
63+
64+
- name: Load `gateway` and `ui` containers
65+
if: inputs.regen_cache == false
66+
run: |
67+
docker load < gateway-container.tar
68+
docker load < ui-container.tar
69+
70+
# This allows us to use 'no-build' on subsequent steps
71+
- name: Build needed docker images
72+
working-directory: ui
73+
run: |
74+
docker compose -f fixtures/docker-compose.e2e.yml -f fixtures/docker-compose.ui.yml build fixtures mock-inference-provider
75+
76+
- name: Set common fixture environment variables
77+
working-directory: ui
78+
run: |
79+
# Environment variables shared by the gateway and ui containers
80+
echo "TENSORZERO_CLICKHOUSE_URL=http://chuser:chpassword@clickhouse:8123/tensorzero_ui_fixtures" >> fixtures/.env
81+
echo "TENSORZERO_GATEWAY_URL=http://gateway:3000" >> fixtures/.env
82+
echo "TENSORZERO_GATEWAY_TAG=sha-${{ github.sha }}" >> fixtures/.env
83+
echo "TENSORZERO_UI_TAG=sha-${{ github.sha }}" >> fixtures/.env
84+
# We need these set in the ui container, so that we construct the correct optimizer config
85+
# to pass to 'experimentalLaunchOptimizationWorkflow'
86+
echo "FIREWORKS_BASE_URL=http://mock-inference-provider:3030/fireworks/" >> fixtures/.env
87+
echo "OPENAI_BASE_URL=http://mock-inference-provider:3030/openai/" >> fixtures/.env
88+
echo "FIREWORKS_ACCOUNT_ID=fake_fireworks_account" >> fixtures/.env
89+
echo "VITE_TENSORZERO_FORCE_CACHE_ON=1" >> fixtures/.env
90+
91+
- name: Regenerate model inference cache
92+
working-directory: ui
93+
if: inputs.regen_cache == true
94+
run: |
95+
echo "FIREWORKS_ACCOUNT_ID=${{ secrets.FIREWORKS_ACCOUNT_ID }}" >> fixtures/.env-gateway
96+
echo "FIREWORKS_API_KEY=${{ secrets.FIREWORKS_API_KEY }}" >> fixtures/.env-gateway
97+
echo "OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" >> fixtures/.env-gateway
98+
echo "S3_ACCESS_KEY_ID=${{ secrets.S3_ACCESS_KEY_ID }}" >> fixtures/.env-gateway
99+
echo "S3_SECRET_ACCESS_KEY=${{ secrets.S3_SECRET_ACCESS_KEY }}" >> fixtures/.env-gateway
100+
./fixtures/regenerate-model-inference-cache.sh
101+
# Take down and destroy the containers, so that our subsequent test run starts with a fresh ClickHouse
102+
# server, and inserts our regenerated fixtures from scratch
103+
docker compose -f ./fixtures/docker-compose.e2e.yml -f ./fixtures/docker-compose.ui.yml down
104+
docker compose -f ./fixtures/docker-compose.e2e.yml -f ./fixtures/docker-compose.ui.yml rm -f
105+
106+
107+
- name: Upload new model inference cache
108+
if: inputs.regen_cache == true
109+
uses: namespace-actions/upload-artifact@9a78c62e083914789d908952f9773e42744b9f68
110+
with:
111+
name: model-inference-cache
112+
path: |
113+
ui/fixtures/model_inference_cache_e2e.jsonl
114+
115+
- name: Start dependency Docker containers and apply fixtures
116+
working-directory: ui
117+
run: |
118+
# Environment variables only used by the gateway container
119+
# We deliberately leave these unset when starting the UI container, to ensure
120+
# that it doesn't depend on them being set
121+
# When the secrets are not passed in to this workflow
122+
# (which happens when we test our existing cache file in PR CI),
123+
# we set them to dummy values
124+
echo "FIREWORKS_ACCOUNT_ID=${{ secrets.FIREWORKS_ACCOUNT_ID || 'not_used' }}" >> fixtures/.env-gateway
125+
echo "FIREWORKS_API_KEY=${{ secrets.FIREWORKS_API_KEY || 'not_used' }}" >> fixtures/.env-gateway
126+
echo "OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY || 'not_used' }}" >> fixtures/.env-gateway
127+
echo "S3_ACCESS_KEY_ID=${{ secrets.S3_ACCESS_KEY_ID }}" >> fixtures/.env-gateway
128+
echo "S3_SECRET_ACCESS_KEY=${{ secrets.S3_SECRET_ACCESS_KEY }}" >> fixtures/.env-gateway
129+
docker compose -f fixtures/docker-compose.e2e.yml up --no-build -d
130+
docker compose -f fixtures/docker-compose.e2e.yml wait fixtures
131+
132+
- name: Start UI Docker container
133+
working-directory: ui
134+
run: |
135+
docker compose -f fixtures/docker-compose.ui.yml up --no-build -d --wait
136+
137+
- name: Run UI E2E tests
138+
id: e2e_tests
139+
env:
140+
TENSORZERO_CI: 1
141+
run: pnpm ui:test:e2e --grep-invert "@credentials"
142+
143+
- name: Print Docker Compose logs
144+
if: always()
145+
working-directory: ui
146+
run: docker compose -f fixtures/docker-compose.e2e.yml -f fixtures/docker-compose.ui.yml logs -t
147+
148+
- name: Print container health checks
149+
if: always()
150+
working-directory: ui
151+
run: docker inspect --format "{{json .State.Health }}" $(docker compose -f fixtures/docker-compose.e2e.yml -f fixtures/docker-compose.ui.yml ps -q ui) | jq
152+
153+
- name: Make sure the current commit short hash is in the Docker Compose gateway logs
154+
if: always()
155+
working-directory: ui
156+
run: |
157+
SHORT_HASH=$(echo "${{ github.sha }}" | cut -c1-7)
158+
docker compose -f fixtures/docker-compose.e2e.yml logs gateway | grep "(commit: ${SHORT_HASH})" || {
159+
echo "ERROR: Commit hash ${SHORT_HASH} not found in gateway logs"
160+
exit 1
161+
}
162+
163+
- name: Print ClickHouse error logs
164+
if: always()
165+
run: docker exec fixtures-clickhouse-1 cat /var/log/clickhouse-server/clickhouse-server.err.log
166+
167+
- name: Print ClickHouse trace logs
168+
if: always()
169+
run: docker exec fixtures-clickhouse-1 cat /var/log/clickhouse-server/clickhouse-server.log
170+
171+
- name: Upload Playwright artifacts
172+
if: failure()
173+
uses: namespace-actions/upload-artifact@9a78c62e083914789d908952f9773e42744b9f68
174+
with:
175+
name: playwright-report
176+
path: |
177+
ui/playwright-report/
178+
ui/test-results/
179+
retention-days: 7

0 commit comments

Comments
 (0)