Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 8 additions & 65 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ jobs:
uses: actions/checkout@v4
with:
clean: 'true'
submodules: recursive

- name: Set up Go
uses: actions/setup-go@v5
Expand Down Expand Up @@ -83,8 +82,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Go
uses: actions/setup-go@v5
Expand All @@ -106,8 +103,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Go
uses: actions/setup-go@v5
Expand All @@ -129,8 +124,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Go
uses: actions/setup-go@v5
Expand All @@ -150,72 +143,22 @@ jobs:
fail_ci_if_error: false
# token: ${{ secrets.CODECOV_TOKEN }} # Uncomment if required for private repos

e2e:
name: E2E Tests (gts-spec)
gts-spec-tests:
name: GTS Spec Tests
runs-on: ubuntu-latest
env:
PYTHONDONTWRITEBYTECODE: 1
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true

- name: Build release binary
run: go build -o ./bin/gts ./cmd/gts

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install pytest and dependencies
run: pip install pytest requests httprunner

- name: Run e2e tests
run: |
# Start server in background with logs
./bin/gts server --port 8000 > .server.log 2>&1 &
SERVER_PID=$!
echo "Started GTS server with PID $SERVER_PID"

# Wait for server to be ready
echo "Waiting for GTS server to start..."
for i in $(seq 1 30); do
if ! kill -0 $SERVER_PID 2>/dev/null; then
echo "ERROR: Server process died unexpectedly"
echo "=== Server logs ==="
cat .server.log || true
exit 1
fi
if curl -sf http://127.0.0.1:8000/entities > /dev/null 2>&1; then
echo "GTS server is ready!"
break
fi
if [ $i -eq 30 ]; then
echo "ERROR: GTS server failed to start within 30 seconds"
echo "=== Server logs ==="
cat .server.log || true
kill $SERVER_PID 2>/dev/null || true
exit 1
fi
echo "Attempt $i/30: Server not ready yet, waiting..."
sleep 1
done

# Run tests
pytest -p no:cacheprovider ./.gts-spec/tests -v
TEST_EXIT=$?

# Stop server
echo "Stopping GTS server..."
kill $SERVER_PID 2>/dev/null || true
wait $SERVER_PID 2>/dev/null || true

exit $TEST_EXIT
# Builds the gts binary, pulls the gts-spec test-runner image from
# GHCR (tag from .gts-spec-version), starts the server natively, waits
# for readiness, then runs pytest inside the container against
# host.docker.internal:$PORT. See Makefile.
- name: Run gts-spec tests via docker
run: make gts-spec-tests
3 changes: 0 additions & 3 deletions .gitmodules

This file was deleted.

1 change: 0 additions & 1 deletion .gts-spec
Submodule .gts-spec deleted from 23ed72
1 change: 1 addition & 0 deletions .gts-spec-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v0.12.0
77 changes: 40 additions & 37 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,59 +6,62 @@ Guidance for Claude Code when working in this repository.

`gts-go` is the Go reference implementation of [GTS](https://github.com/GlobalTypeSystem/gts-spec) — library (`gts/`), CLI (`cmd/gts`), and an HTTP server (`cmd/gts-server` / `gts server`) that answers the REST API exercised by the shared gts-spec conformance suite.

`.gts-spec/` is the spec vendored as a git submodule; `tests/` inside it is the conformance suite. See `README.md` for API/CLI details and `make help` for all targets.
The spec version this implementation targets is pinned in
[`.gts-spec-version`](.gts-spec-version) (used verbatim as the GHCR tag for
the test-runner image). Bumping the pin and running the suite is how new
spec features land. See `README.md` for API/CLI details and `make help` for
all targets.

## Running the gts-spec Test Suite

The short form is `make e2e PORT=8001` (PORT defaults to 8000; override if busy — the target fails fast if the port is already in use). It bootstraps the venv, rebuilds, starts the server, runs pytest, and shuts everything down.

### Bootstrap the venv (first time only)

Tests depend on `httprunner`. Installed into `.gts-spec/.venv/` (gitignored by the submodule).
`make gts-spec-tests` runs the gts-spec conformance suite against a freshly
built server. Tests come from the published runner image
`ghcr.io/globaltypesystem/gts-spec-tests`; the tag comes from
[`.gts-spec-version`](.gts-spec-version) as an immutable
`vMAJOR.MINOR.PATCH` — every commit reproduces the same test run, and
rolling forward is a deliberate bump of that file. Requires a working
Docker daemon plus the Go toolchain (the target builds the server binary
before pulling the test-runner image).

```bash
make e2e-venv # uses python3 by default
make e2e-venv PYTHON=python3.11 # Python 3.11 is the safest (httprunner still pins pydantic<2)
make gts-spec-tests # full suite on :8000
make gts-spec-tests PORT=8001 # different port
make gts-spec-tests TEST=test_op1_id_validation.py # single file / selector
```

### Run pytest manually against a running server

Useful when iterating on a single test without the full `make e2e` cycle.
Opt into the rolling minor tag, try a different patch, or test a fork:

```bash
make build
./bin/gts server --port 8001 &

PYTEST=".gts-spec/.venv/bin/python -m pytest"

# Whole suite
$PYTEST .gts-spec/tests --gts-base-url http://127.0.0.1:8001

# One file / one class
$PYTEST .gts-spec/tests/test_refimpl_x_gts_final_abstract.py --gts-base-url http://127.0.0.1:8001
$PYTEST .gts-spec/tests/test_op12_schema_vs_schema_validation.py::TestCaseOp12_FinalBase_RejectDerived --gts-base-url http://127.0.0.1:8001
make gts-spec-tests GTS_SPEC_VERSION=v0.11 # rolling vMAJOR.MINOR
make gts-spec-tests GTS_SPEC_VERSION=v0.11.0 # specific patch
make gts-spec-tests GTS_SPEC_IMAGE=ghcr.io/your-fork/gts-spec-tests
```

`GTS_BASE_URL` env var works too. The server holds state in memory with no reset endpoint — restart between full-suite runs.
Iterating on the test suite itself? Mount a local checkout over `/tests`:

### Open-files limit on macOS
```bash
make gts-spec-tests GTS_SPEC_TESTS_DIR=../gts-spec/tests
```

Before running the full suite, raise the FD limit in the calling shell:
For tight test-edit loops, keep a long-running server in one terminal and
re-run targeted tests in another:

```bash
ulimit -n 4096
```
# Terminal 1
make gts-server PORT=8001

`httprunner` leaks a keep-alive socket per test class (the underlying
`requests.Session` is never closed), so FDs grow linearly. macOS's
default 256 soft cap is hit around test ~240 with `EMFILE: Too many
open files`. Linux defaults (1024+) are usually fine. `make e2e` runs
its commands in a subshell, so the `ulimit` must be set in the parent
shell that invokes `make`. Don't bake `ulimit` into the Makefile —
it's an environment concern, not a build step.
# Terminal 2
make gts-spec-tests-run PORT=8001 TEST=test_op12_type_derivation_validation.py
```

## Working in This Repo

- `.gts-spec` is a submodule. Bump with `make update-spec`, then rerun `make e2e` to pick up new spec tests.
- Handlers in `server/` stay thin — logic goes in `gts/` where it is unit-testable. New REST behavior usually already has coverage in `.gts-spec/tests/`; run the relevant file before and after to confirm.
- `make check` is the full local gate: fmt + vet + lint + test + e2e.
- The spec is no longer a git submodule. To bump the conformance target,
edit `.gts-spec-version` and run `make gts-spec-tests` — the new image
is pulled on demand.
- Handlers in `server/` stay thin — logic goes in `gts/` where it is
unit-testable. New REST behavior usually already has coverage in the
gts-spec test suite; iterating on a single test via
`make gts-spec-tests TEST=...` is the fastest signal.
- `make check` is the full local gate: fmt + vet + lint + test +
gts-spec-tests.
Loading
Loading