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
44 changes: 9 additions & 35 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,6 @@ jobs:
name: Integration Tests
runs-on: ubuntu-latest

services:
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5

postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: quotient_test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- name: Checkout code
uses: actions/checkout@v7
Expand All @@ -78,21 +53,20 @@ jobs:
- name: Install dependencies
run: go mod download

- name: Set up Docker Compose
uses: docker/setup-compose-action@v2

- name: Run integration tests
# -p 1 runs one package binary at a time. These packages share a single
# Postgres database and a single Redis instance, and they use fixed
# names for both (the `tasks` and `results` lists, one schema). Running
# them concurrently lets one package consume the other's queued tasks
# and reset its rows.
run: go test -v -race -p 1 ./tests/integration/... ./engine/... -timeout 10m
run: make test-integration
env:
REDIS_HOST: localhost
REDIS_PORT: 6379
REDIS_PORT: 6380
REDIS_PASSWORD: redis_password
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
POSTGRES_DB: quotient_test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: engine
POSTGRES_USER: engineuser
POSTGRES_PASSWORD: postgres_password

security-scanner:
name: Security Scanner
Expand Down
31 changes: 7 additions & 24 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,37 +1,20 @@
.PHONY: test test-unit test-integration test-coverage clean test-deps-start test-deps-stop test-deps-wait
.PHONY: test test-unit test-integration test-coverage clean test-deps-start test-deps-stop

test:
go test -race -p 1 ./...
go test -v -race -p 1 ./...

test-unit:
go test -race -short ./engine/... ./www/... ./runner/...
go test -v -race -short ./engine/... ./www/... ./runner/...

test-integration: test-deps-start test-deps-wait
POSTGRES_PASSWORD=postgres go test -race ./tests/integration/... -timeout 10m
test-integration: test-deps-start
go test -v -race -p 1 ./tests/integration/... ./engine/... -timeout 10m
@$(MAKE) test-deps-stop

test-deps-start:
@docker ps -q -f name=quotient-test-postgres | grep -q . || \
docker run -d --name quotient-test-postgres \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=quotient_test \
-p 5432:5432 \
postgres:16-alpine
@docker ps -q -f name=quotient-test-redis | grep -q . || \
docker run -d --name quotient-test-redis \
-p 6379:6379 \
redis:7-alpine

test-deps-wait:
@echo "Waiting for Postgres..."
@until docker exec quotient-test-postgres pg_isready -U postgres > /dev/null 2>&1; do sleep 1; done
@echo "Waiting for Redis..."
@until docker exec quotient-test-redis redis-cli ping > /dev/null 2>&1; do sleep 1; done
@echo "Services ready."
docker compose up test-redis test-db --wait -d

test-deps-stop:
@docker stop quotient-test-postgres quotient-test-redis 2>/dev/null || true
@docker rm quotient-test-postgres quotient-test-redis 2>/dev/null || true
docker compose down test-redis test-db

test-coverage:
go test -race -p 1 -coverprofile=coverage.out ./...
Expand Down
27 changes: 27 additions & 0 deletions docker-compose.base.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
services:
db-base:
image: postgres:17
env_file:
- .env
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 5s
timeout: 5s
retries: 5
start_period: 3s
networks:
- quotient_network

redis-base:
image: redis:alpine
env_file:
- .env
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD:?REDIS_PASSWORD variable is not set}"]
healthcheck:
test: ["CMD-SHELL", "redis-cli -a $$REDIS_PASSWORD ping | grep -q PONG"]
interval: 5s
timeout: 5s
retries: 5
start_period: 3s
networks:
- quotient_network
50 changes: 26 additions & 24 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
services:
test-db:
extends:
file: docker-compose.base.yml
service: db-base
profiles:
- test
ports:
- "127.0.0.1:5432:5432"

db:
extends:
file: docker-compose.base.yml
service: db-base
container_name: quotient_database
image: postgres:17
restart: always
env_file:
- .env
networks:
- quotient_network
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 5s
timeout: 5s
retries: 5
start_period: 3s

server:
container_name: quotient_server
Expand All @@ -38,23 +39,24 @@ services:
- ./engine:/app/engine
- ./static:/app/static

test-redis:
extends:
file: docker-compose.base.yml
service: redis-base
profiles:
- test
ports:
# Don't conflict with actual redis instance
- "127.0.0.1:6380:6379"

redis:
image: redis:alpine
container_name: quotient_redis
extends:
file: docker-compose.base.yml
service: redis-base
restart: always
env_file:
- .env
container_name: quotient_redis
ports:
- "127.0.0.1:6379:6379"
networks:
- quotient_network
command: ["redis-server", "--requirepass", "${REDIS_PASSWORD:?REDIS_PASSWORD variable is not set}"]
healthcheck:
test: ["CMD-SHELL", "redis-cli -a $$REDIS_PASSWORD ping | grep -q PONG"]
interval: 5s
timeout: 5s
retries: 5
start_period: 3s

runner:
build:
Expand Down
40 changes: 11 additions & 29 deletions tests/testutil/testutil.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package testutil

import (
"cmp"
"fmt"
"os"
"sync/atomic"
Expand Down Expand Up @@ -30,17 +31,13 @@ func (r *RedisContainer) Close() error {
func startRedis(t *testing.T) *RedisContainer {
t.Helper()

host := os.Getenv("REDIS_HOST")
if host == "" {
host = "localhost"
}
port := os.Getenv("REDIS_PORT")
if port == "" {
port = "6379"
}
host := cmp.Or(os.Getenv("REDIS_HOST"), "localhost")
port := cmp.Or(os.Getenv("REDIS_PORT"), "6380")
password := cmp.Or(os.Getenv("REDIS_PASSWORD"), "redis_password")

client := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%s", host, port),
Addr: fmt.Sprintf("%s:%s", host, port),
Password: password,
})

return &RedisContainer{Client: client}
Expand All @@ -60,26 +57,11 @@ func (p *PostgresContainer) Close() error {
func startPostgres(t *testing.T) *PostgresContainer {
t.Helper()

host := os.Getenv("POSTGRES_HOST")
if host == "" {
host = "localhost"
}
port := os.Getenv("POSTGRES_PORT")
if port == "" {
port = "5432"
}
dbname := os.Getenv("POSTGRES_DB")
if dbname == "" {
dbname = "quotient_test"
}
user := os.Getenv("POSTGRES_USER")
if user == "" {
user = "postgres"
}
password := os.Getenv("POSTGRES_PASSWORD")
if password == "" {
password = "postgres"
}
host := cmp.Or(os.Getenv("POSTGRES_HOST"), "localhost")
port := cmp.Or(os.Getenv("POSTGRES_PORT"), "5432")
dbname := cmp.Or(os.Getenv("POSTGRES_DB"), "engine")
user := cmp.Or(os.Getenv("POSTGRES_USER"), "engineuser")
password := cmp.Or(os.Getenv("POSTGRES_PASSWORD"), "postgres_password")

connString := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
Expand Down