Skip to content

Commit e3542b1

Browse files
committed
test: comprehensive E2E test suite and CI improvements
E2E tests (6 new test files, 1864 lines): - test_encryption.py: 17 tests — lifecycle, upload/download, material URLs, key rotation, Redis cache inspection (verifies no plaintext leakage) - test_project_isolation.py: 20 IDOR regression tests across all endpoints - test_disk_artifact.py: disk CRUD, artifact ls/grep/glob, session configs - test_agent_skills.py: ZIP upload, pagination, file download, deletion - test_learning_spaces.py: CRUD, skill associations, meta JSONB filtering - test_users.py: user listing, resource counts, cascade delete CI improvements: - Parallel Docker image builds (4 images with GHA layer cache) - .dockerignore for API and CORE to reduce build context - Dockerfile.e2e: thin test runner image with tests as volume mount - docker-compose.test.yml: 8-service stack with mock LLM, disabled Argon2
1 parent 3f4023a commit e3542b1

15 files changed

Lines changed: 3073 additions & 188 deletions

.github/workflows/e2e-test.yaml

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,43 @@ jobs:
3232
- name: Set up Docker Buildx
3333
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd
3434

35-
- name: Build Images
35+
- name: Build Docker Images (parallel)
3636
run: |
37-
cd src/server
38-
docker compose -f docker-compose.test.yml build
37+
docker buildx build \
38+
--load \
39+
--cache-from type=gha,scope=e2e-core \
40+
--cache-to type=gha,mode=max,scope=e2e-core \
41+
-t acontext-e2e-test-core:latest \
42+
./src/server/core &
43+
PID_CORE=$!
44+
45+
docker buildx build \
46+
--load \
47+
--cache-from type=gha,scope=e2e-api \
48+
--cache-to type=gha,mode=max,scope=e2e-api \
49+
-t acontext-e2e-test-api:latest \
50+
./src/server/api/go &
51+
PID_API=$!
52+
53+
docker buildx build \
54+
--load \
55+
--file ./src/server/api/go/Dockerfile.admin \
56+
--cache-from type=gha,scope=e2e-admin \
57+
--cache-to type=gha,mode=max,scope=e2e-admin \
58+
-t acontext-e2e-test-admin:latest \
59+
./src/server/api/go &
60+
PID_ADMIN=$!
61+
62+
docker buildx build \
63+
--load \
64+
--cache-from type=gha,scope=e2e-runner \
65+
--cache-to type=gha,mode=max,scope=e2e-runner \
66+
-t acontext-e2e-test-runner:latest \
67+
-f ./src/server/tests/Dockerfile.e2e \
68+
./src/server/tests &
69+
PID_RUNNER=$!
70+
71+
wait $PID_CORE $PID_API $PID_ADMIN $PID_RUNNER
3972
4073
- name: Run E2E Test
4174
run: |
@@ -47,9 +80,3 @@ jobs:
4780
run: |
4881
cd src/server
4982
docker compose -f docker-compose.test.yml logs
50-
51-
- name: Teardown
52-
if: always()
53-
run: |
54-
cd src/server
55-
docker compose -f docker-compose.test.yml down --timeout 10

src/client/acontext-cli/internal/docker/docker-compose.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ services:
231231
CORE_BASE_URL: http://acontext-server-core:8000
232232
OTEL_EXPORTER_OTLP_ENDPOINT: acontext-server-jaeger:4317
233233
ARTIFACT_MAX_UPLOAD_SIZE_BYTES: ${ARTIFACT_MAX_UPLOAD_SIZE_BYTES:-16777216}
234+
APP_EXTERNALURL: ${APP_EXTERNALURL:-}
234235
ports:
235236
- "${API_EXPORT_PORT:-8029}:8029"
236237
healthcheck:

src/server/docker-compose.test.yml

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ services:
6969

7070
# --- Python Core ---
7171
core:
72+
image: acontext-e2e-test-core:latest
7273
build:
7374
context: ./core
7475
environment:
@@ -95,6 +96,7 @@ services:
9596

9697
# --- Go API ---
9798
api:
99+
image: acontext-e2e-test-api:latest
98100
build:
99101
context: ./api/go
100102
environment:
@@ -127,6 +129,7 @@ services:
127129
ARTIFACT_MAX_UPLOAD_SIZE_BYTES: 16777216
128130
ROOT_API_BEARER_TOKEN: test-token
129131
APP_ROOT_SECRETPEPPER: test-pepper
132+
APP_EXTERNALURL: http://api:8029
130133
depends_on:
131134
core: { condition: service_healthy }
132135
healthcheck:
@@ -135,21 +138,73 @@ services:
135138
timeout: 5s
136139
retries: 5
137140

141+
# --- Go Admin API ---
142+
admin:
143+
image: acontext-e2e-test-admin:latest
144+
build:
145+
context: ./api/go
146+
dockerfile: Dockerfile.admin
147+
environment:
148+
APP_ENV: debug
149+
API_EXPORT_PORT: 8028
150+
DATABASE_HOST: pg
151+
DATABASE_USER: acontext
152+
DATABASE_PASSWORD: helloworld
153+
DATABASE_NAME: acontext_test
154+
DATABASE_EXPORT_PORT: 5432
155+
DATABASE_ENABLE_TLS: "false"
156+
REDIS_HOST: redis
157+
REDIS_PASSWORD: helloworld
158+
REDIS_EXPORT_PORT: 6379
159+
REDIS_ENABLE_TLS: "false"
160+
RABBITMQ_HOST: rabbitmq
161+
RABBITMQ_USER: acontext
162+
RABBITMQ_PASSWORD: helloworld
163+
RABBITMQ_VHOST: /
164+
RABBITMQ_VHOST_ENCODED: "%2F"
165+
RABBITMQ_EXPORT_PORT: 5672
166+
RABBITMQ_ENABLE_TLS: "false"
167+
S3_ENDPOINT: http://seaweedfs:9000
168+
S3_INTERNAL_ENDPOINT: http://seaweedfs:9000
169+
S3_REGION: us-east-1
170+
S3_ACCESS_KEY: acontext
171+
S3_SECRET_KEY: helloworld
172+
S3_BUCKET: acontext-assets
173+
CORE_BASE_URL: http://core:8000
174+
APP_TELEMETRY_ENABLED: "false"
175+
ENABLE_ARGON2_VERIFICATION: "false"
176+
ARTIFACT_MAX_UPLOAD_SIZE_BYTES: 16777216
177+
ROOT_API_BEARER_TOKEN: test-token
178+
APP_ROOT_SECRETPEPPER: test-pepper
179+
depends_on:
180+
core: { condition: service_healthy }
181+
healthcheck:
182+
test: [ "CMD-SHELL", "wget -q -O- http://localhost:8028/health || exit 1" ]
183+
interval: 10s
184+
timeout: 5s
185+
retries: 5
186+
138187
# --- Test Runner ---
139188
tests:
140-
image: python:3.12-slim
189+
image: acontext-e2e-test-runner:latest
190+
build:
191+
context: ./tests
192+
dockerfile: Dockerfile.e2e
141193
environment:
142194
API_URL: http://api:8029
195+
ADMIN_URL: http://admin:8028
143196
CORE_URL: http://core:8000
144197
DB_URL: postgresql://acontext:helloworld@pg:5432/acontext_test
198+
REDIS_URL: redis://:helloworld@redis:6379
145199
TEST_TOKEN: test-token
146200
volumes:
147201
- ./tests:/app/tests
148202
- ./pytest.ini:/app/pytest.ini
149203
working_dir: /app
150204
depends_on:
151205
api: { condition: service_healthy }
152-
command: [ "sh", "-c", "pip install httpx asyncpg pydantic pytest pytest-asyncio==0.21.* && pytest tests/e2e/test_simple.py -v --asyncio-mode=auto" ]
206+
admin: { condition: service_healthy }
207+
command: [ "pytest", "tests/e2e/test_simple.py", "tests/e2e/test_encryption.py", "tests/e2e/test_session_events.py", "tests/e2e/test_agent_skills.py", "tests/e2e/test_learning_spaces.py", "tests/e2e/test_users.py", "tests/e2e/test_disk_artifact.py", "tests/e2e/test_project_isolation.py", "-v", "--asyncio-mode=auto" ]
153208

154209
networks:
155210
default:

src/server/docker-compose.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ services:
249249
CORE_BASE_URL: http://acontext-server-core:8000
250250
OTEL_EXPORTER_OTLP_ENDPOINT: acontext-server-jaeger:4317
251251
ARTIFACT_MAX_UPLOAD_SIZE_BYTES: ${ARTIFACT_MAX_UPLOAD_SIZE_BYTES:-16777216}
252+
APP_EXTERNALURL: ${APP_EXTERNALURL:-}
252253
ports:
253254
- "${API_EXPORT_PORT:-8029}:8029"
254255
healthcheck:

src/server/tests/Dockerfile.e2e

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM python:3.12-slim
2+
3+
WORKDIR /app
4+
5+
COPY requirements-e2e.txt .
6+
RUN pip install --no-cache-dir -r requirements-e2e.txt
7+
8+
# Tests are mounted at runtime via docker-compose volume, not copied in.
9+
# This lets the image be cached even when test code changes.

0 commit comments

Comments
 (0)