Skip to content

Commit 9bfaa1b

Browse files
committed
feat: full dockerized end to end tests
1 parent 2820b7c commit 9bfaa1b

15 files changed

Lines changed: 1053 additions & 132 deletions

File tree

.dockerignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Keep the Docker build context small and platform-agnostic: never ship host
2+
# build artifacts or VCS metadata into the image.
3+
target/
4+
**/target/
5+
.git/
6+
.github/
7+
*.md

.github/workflows/e2e.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: end-to-end tests
2+
3+
on:
4+
pull_request:
5+
6+
concurrency:
7+
group: ${{ github.workflow }}-${{ github.ref }}
8+
cancel-in-progress: true
9+
10+
jobs:
11+
docker-e2e:
12+
name: docker-e2e
13+
runs-on: ubuntu-latest
14+
if: ${{ !startsWith(github.event.pull_request.title, 'chore:') }}
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v7
18+
19+
- name: Run Docker e2e (server + client over HTTP)
20+
run: make test-e2e

Cargo.lock

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ SHELL := /bin/bash
22

33
.PHONY: help
44
help: ## Show this help
5-
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
5+
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
66
sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-35s\033[0m %s\n", $$1, $$2}'
77

88
.PHONY: clean
@@ -43,6 +43,12 @@ test-unit: ## Run unit tests
4343
test-integration: ## Run integration tests
4444
cargo test --features integration --test '*_integration' -- --nocapture
4545

46+
.PHONY: test-e2e
47+
test-e2e: ## Run the Docker end-to-end test (generated server + client over HTTP)
48+
docker compose \
49+
-f crates/oapi-codegen/tests/integration/docker-compose.yml \
50+
up --build --exit-code-from client --abort-on-container-exit
51+
4652
.PHONY: update-generated
4753
update-generated: ## Refresh generated files from the coverage fixtures
4854
UPDATE_GENERATED=1 cargo test -p oapi-codegen --test coverage
@@ -52,7 +58,8 @@ generate-example: ## Regenerate the composed bookstore example from its OpenAPI
5258
cd examples/bookstore && \
5359
cargo run -q -p oapi-codegen -- schemas/common.yaml --config oapi-codegen-common.yaml && \
5460
cargo run -q -p oapi-codegen -- schemas/catalog.yaml --config oapi-codegen-catalog.yaml && \
55-
cargo run -q -p oapi-codegen -- openapi.yaml --config oapi-codegen-server.yaml
61+
cargo run -q -p oapi-codegen -- openapi.yaml --config oapi-codegen-server.yaml && \
62+
cargo run -q -p oapi-codegen -- openapi.yaml --config oapi-codegen-client.yaml
5663

5764
.PHONY: verify-generated
5865
verify-generated: ## Regenerate all generated code and fail if it drifts from what is committed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Compile the generated blocking `reqwest` client and its e2e test, then run the
2+
# test against the server named by BOOKSTORE_BASE_URL (set in docker-compose.yml).
3+
# The image keeps the full toolchain because it runs `cargo test` at container
4+
# start; pre-building with `--no-run` means startup goes straight to the tests.
5+
# The build context is the repository root (see docker-compose.yml).
6+
7+
FROM rust:1.96-bookworm AS builder
8+
WORKDIR /src
9+
COPY . .
10+
RUN cargo test --no-run -p bookstore-example --features client --test e2e
11+
CMD ["cargo", "test", "-p", "bookstore-example", "--features", "client", "--test", "e2e", "--", "--nocapture"]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: bookstore-e2e
2+
3+
# End-to-end harness: the `server` service runs the generated axum server and the
4+
# `client` service compiles the generated reqwest client + integration test and
5+
# drives every bookstore endpoint over HTTP. Run from the repository root with:
6+
#
7+
# docker compose -f crates/oapi-codegen/tests/integration/docker-compose.yml \
8+
# up --build --exit-code-from client --abort-on-container-exit
9+
#
10+
# The overall exit status is the client's, so CI fails iff the e2e tests fail.
11+
12+
services:
13+
server:
14+
build:
15+
context: ../../../..
16+
dockerfile: crates/oapi-codegen/tests/integration/server/Dockerfile
17+
environment:
18+
BOOKSTORE_ADDR: 0.0.0.0:8080
19+
expose:
20+
- "8080"
21+
22+
client:
23+
build:
24+
context: ../../../..
25+
dockerfile: crates/oapi-codegen/tests/integration/client/Dockerfile
26+
depends_on:
27+
- server
28+
environment:
29+
BOOKSTORE_BASE_URL: http://server:8080
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Build the bookstore server binary from the workspace, then run it from a slim
2+
# runtime image. The build context is the repository root (see docker-compose.yml).
3+
4+
FROM rust:1.96-bookworm AS builder
5+
WORKDIR /src
6+
COPY . .
7+
RUN cargo build --release -p bookstore-example --bin bookstore-server
8+
9+
FROM debian:bookworm-slim AS runtime
10+
WORKDIR /app
11+
COPY --from=builder /src/target/release/bookstore-server /usr/local/bin/bookstore-server
12+
ENV BOOKSTORE_ADDR=0.0.0.0:8080
13+
EXPOSE 8080
14+
CMD ["bookstore-server"]

examples/bookstore/Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,22 @@ publish = false
99
[lints]
1010
workspace = true
1111

12+
[features]
13+
# Compile the generated blocking `reqwest` client (`restclient`) and the e2e
14+
# integration test that drives it. Kept optional so the default build stays lean
15+
# and does not pull in `reqwest`; the Docker e2e image builds with this feature.
16+
client = ["dep:reqwest", "dep:percent-encoding"]
17+
1218
[dependencies]
1319
axum = { version = "0.8.9", features = ["multipart"] }
1420
axum-extra = { version = "0.12.6", features = ["query"] }
1521
serde = { version = "1.0.228", features = ["derive"] }
1622
serde_json = "1.0.150"
23+
tokio = { version = "1.48.0", features = ["rt-multi-thread", "macros", "net", "signal"] }
24+
25+
reqwest = { version = "0.12.28", default-features = false, features = ["blocking", "json", "multipart"], optional = true }
26+
percent-encoding = { version = "2.3.2", optional = true }
27+
28+
[[bin]]
29+
name = "bookstore-server"
30+
path = "src/bin/server.rs"

0 commit comments

Comments
 (0)