From cc78cb076513b1903517498fe980bfc950a1b36a Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 4 May 2026 21:53:01 -0700 Subject: [PATCH 1/4] cache docker layers and parallelize tests --- .github/workflows/integration.yml | 13 ++++++++++++- testing/Makefile | 17 +++++++++++++---- testing/integration/creation_test.go | 3 +++ testing/integration/docker-compose.ci-cache.yml | 16 ++++++++++++++++ testing/integration/registration_test.go | 3 +++ 5 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 testing/integration/docker-compose.ci-cache.yml diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 2679523..ebcc8a3 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -6,6 +6,9 @@ on: push: branches: [main] +permissions: + contents: read + jobs: detect-integration-changes: runs-on: ubuntu-latest @@ -38,18 +41,26 @@ jobs: env: # Compose can be slow on runners (Kafka + topic init + server build) INTEGRATION_READY_TIMEOUT: 120s + # BuildKit + compose build: better layer reuse; GHA cache requires buildx (see below). + DOCKER_BUILDKIT: 1 + COMPOSE_DOCKER_CLI_BUILD: 1 steps: - name: Checkout repo uses: actions/checkout@v4 + # Enables type=gha BuildKit cache used in testing/integration/docker-compose.ci-cache.yml + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Set up Go uses: actions/setup-go@v5 with: go-version-file: go.mod cache: true - # make integration = docker compose up + go test -tags=integration (see testing/Makefile) + # make integration = docker compose up + go test -tags=integration (see testing/Makefile). + # On GitHub Actions, Makefile adds docker-compose.ci-cache.yml for BuildKit GHA layer cache. - name: Run integration tests run: make integration diff --git a/testing/Makefile b/testing/Makefile index 3b3c0c6..088e2e3 100644 --- a/testing/Makefile +++ b/testing/Makefile @@ -5,10 +5,18 @@ _TESTING_ABS := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) REPO_ROOT := $(abspath $(_TESTING_ABS)/..) COMPOSE_BASE := $(REPO_ROOT)/docker-compose.dev.yml COMPOSE_INT := $(REPO_ROOT)/testing/integration/docker-compose.integration.yml +COMPOSE_CI_CACHE := $(REPO_ROOT)/testing/integration/docker-compose.ci-cache.yml COMPOSE_LOAD := $(REPO_ROOT)/testing/load/docker-compose.load.yml INTEGRATION_DIR := $(REPO_ROOT)/testing/integration LOAD_DIR := $(REPO_ROOT)/testing/load +# GitHub Actions sets GITHUB_ACTIONS=true — use BuildKit GHA cache (type=gha) for image builds. +ifeq ($(GITHUB_ACTIONS),true) +COMPOSE_EXTRA := -f $(COMPOSE_CI_CACHE) +else +COMPOSE_EXTRA := +endif + # Default to running all integration tests if no filter is provided TEST ?= all @@ -16,7 +24,7 @@ TEST ?= all # Tear down Compose stacks (absolute -f paths; works from any cwd). teardown-integration: - docker compose --project-directory "$(REPO_ROOT)" -f $(COMPOSE_BASE) -f $(COMPOSE_INT) down + docker compose --project-directory "$(REPO_ROOT)" -f $(COMPOSE_BASE) -f $(COMPOSE_INT) $(COMPOSE_EXTRA) down teardown-load: docker compose --project-directory "$(REPO_ROOT)" -f $(COMPOSE_BASE) -f $(COMPOSE_LOAD) down @@ -30,11 +38,11 @@ teardown: teardown-integration teardown-load # make integration TEST=create (event creation flow only) integration: _up_integration ifeq ($(TEST),register) - cd $(INTEGRATION_DIR) && go test -tags=integration -v -run TestRegistration ./... + cd $(INTEGRATION_DIR) && go test -tags=integration -count=1 -parallel 8 -v -run TestRegistration ./... else ifeq ($(TEST),create) - cd $(INTEGRATION_DIR) && go test -tags=integration -v -run TestEventCreation ./... + cd $(INTEGRATION_DIR) && go test -tags=integration -count=1 -parallel 8 -v -run TestEventCreation ./... else - cd $(INTEGRATION_DIR) && go test -tags=integration -v ./... + cd $(INTEGRATION_DIR) && go test -tags=integration -count=1 -parallel 8 -v ./... endif # Flood the registration endpoint with concurrent requests via k6 @@ -49,6 +57,7 @@ _up_integration: --project-directory "$(REPO_ROOT)" \ -f $(COMPOSE_BASE) \ -f $(COMPOSE_INT) \ + $(COMPOSE_EXTRA) \ up -d --build # Spin up the stack with mock Clark for load tests (leaves containers running) diff --git a/testing/integration/creation_test.go b/testing/integration/creation_test.go index 891dc70..b9c7e3a 100644 --- a/testing/integration/creation_test.go +++ b/testing/integration/creation_test.go @@ -12,6 +12,7 @@ import ( // TestEventCreationFlow_CreateAndRetrieve creates an event and verifies it can be // fetched back with matching fields. func TestEventCreationFlow_CreateAndRetrieve(t *testing.T) { + t.Parallel() body := defaultEvent("Create And Retrieve Test", 50) eventID := createEvent(t, "admin-create-retrieve", body) @@ -42,6 +43,7 @@ func TestEventCreationFlow_CreateAndRetrieve(t *testing.T) { // TestEventCreationFlow_Update creates an event, patches the name and location, // then verifies the updated values are returned. func TestEventCreationFlow_Update(t *testing.T) { + t.Parallel() eventID := createEvent(t, "admin-update", defaultEvent("Update Test Original", 50)) patch, _ := json.Marshal(map[string]interface{}{ @@ -83,6 +85,7 @@ func TestEventCreationFlow_Update(t *testing.T) { // TestEventCreationFlow_Delete creates an event, deletes it, and verifies a // subsequent GET returns 404. Only draft or closed events may be deleted (see DeleteEventByID). func TestEventCreationFlow_Delete(t *testing.T) { + t.Parallel() body := defaultEvent("Delete Test", 50) body["status"] = "draft" eventID := createEvent(t, "admin-delete", body) diff --git a/testing/integration/docker-compose.ci-cache.yml b/testing/integration/docker-compose.ci-cache.yml new file mode 100644 index 0000000..8d1f2a2 --- /dev/null +++ b/testing/integration/docker-compose.ci-cache.yml @@ -0,0 +1,16 @@ +# CI-only: enable BuildKit GitHub Actions cache for custom images (see .github/workflows/integration.yml). +# Loaded when CI=true (GitHub Actions sets this automatically). Safe to omit locally. +services: + server: + build: + cache_from: + - type=gha,scope=server + cache_to: + - type=gha,mode=max,scope=server + + mock-clark: + build: + cache_from: + - type=gha,scope=mock-clark + cache_to: + - type=gha,mode=max,scope=mock-clark diff --git a/testing/integration/registration_test.go b/testing/integration/registration_test.go index 735d0d1..2807cb7 100644 --- a/testing/integration/registration_test.go +++ b/testing/integration/registration_test.go @@ -15,6 +15,7 @@ func isRegistrationSubmitted(status int) bool { // TestRegistrationFlow_BasicRegistration creates an event, registers a user, // and verifies the registration is accepted by the Kafka consumer. func TestRegistrationFlow_BasicRegistration(t *testing.T) { + t.Parallel() eventID := createEvent(t, "admin-basic-reg", defaultEvent("Basic Registration Test", 100)) status, requestID := registerForEvent(eventID, "user-basic-reg", "Alice Smith", "alice@example.com") @@ -37,6 +38,7 @@ func TestRegistrationFlow_BasicRegistration(t *testing.T) { // TestRegistrationFlow_DuplicateRegistration verifies that registering the same // user for the same event twice is rejected with 409. func TestRegistrationFlow_DuplicateRegistration(t *testing.T) { + t.Parallel() eventID := createEvent(t, "admin-dup-reg", defaultEvent("Duplicate Registration Test", 100)) // first registration @@ -60,6 +62,7 @@ func TestRegistrationFlow_DuplicateRegistration(t *testing.T) { // TestRegistrationFlow_CapacityFull creates an event with capacity 1, fills it, // then verifies a second user's registration is rejected as capacity_full. func TestRegistrationFlow_CapacityFull(t *testing.T) { + t.Parallel() eventID := createEvent(t, "admin-cap-full", defaultEvent("Capacity Full Test", 1)) // register first user — should be accepted From 719ee07106424a29eb8f092994b31b71f62c93d8 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 4 May 2026 22:14:27 -0700 Subject: [PATCH 2/4] test --- testing/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/testing/README.md b/testing/README.md index a532636..077539e 100644 --- a/testing/README.md +++ b/testing/README.md @@ -1,7 +1,5 @@ # Testing Guide -## Usage - To run integration tests: ```bash From 6150c201ad043155a680e0e1e70daec7c0f8a6ce Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 4 May 2026 22:41:48 -0700 Subject: [PATCH 3/4] added docker cache action --- .github/workflows/integration.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index ebcc8a3..40ba3de 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -49,6 +49,11 @@ jobs: - name: Checkout repo uses: actions/checkout@v4 + - name: Cache Docker images + uses: ScribeMD/docker-cache@0.5.0 + with: + key: docker-cache-${{ runner.os }}-${{ hashFiles('docker-compose.yml', 'docker-compose.dev.yml', 'testing/integration/docker-compose.integration.yml', 'testing/integration/docker-compose.ci-cache.yml') }} + # Enables type=gha BuildKit cache used in testing/integration/docker-compose.ci-cache.yml - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -59,10 +64,21 @@ jobs: go-version-file: go.mod cache: true + - name: Pull and run services + run: | + docker compose \ + --project-directory "${{ github.workspace }}" \ + -f docker-compose.dev.yml \ + -f testing/integration/docker-compose.integration.yml \ + -f testing/integration/docker-compose.ci-cache.yml \ + up -d --build + # make integration = docker compose up + go test -tags=integration (see testing/Makefile). # On GitHub Actions, Makefile adds docker-compose.ci-cache.yml for BuildKit GHA layer cache. - name: Run integration tests - run: make integration + run: | + cd testing/integration + go test -tags=integration -count=1 -parallel 8 -v ./... - name: Tear down Compose if: always() From 7a81953fe366174ffedc51a853dd8d3912e262cb Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 4 May 2026 22:48:46 -0700 Subject: [PATCH 4/4] speed test --- testing/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing/README.md b/testing/README.md index 077539e..a532636 100644 --- a/testing/README.md +++ b/testing/README.md @@ -1,5 +1,7 @@ # Testing Guide +## Usage + To run integration tests: ```bash