🧱 add tests & ci changes
All checks were successful
CI / Lint (push) Successful in 21s
CI / Helm Lint (push) Successful in 6s
CI / Build (push) Successful in 1m48s
CI / Test (push) Successful in 44s

This commit is contained in:
Christian van Dijk
2026-02-23 22:52:54 +01:00
parent dbbe991a3d
commit 59ddc66a8e
10 changed files with 309 additions and 72 deletions

View File

@@ -77,32 +77,7 @@ jobs:
test:
name: Test
runs-on: ubuntu-latest
needs: build
services:
postgres:
image: postgres:15-alpine
env:
POSTGRES_DB: handheld_devices
POSTGRES_USER: devices_user
POSTGRES_PASSWORD: devices_password
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U devices_user -d handheld_devices"
--health-interval 5s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 5
needs: lint
steps:
- uses: actions/checkout@v4
@@ -112,25 +87,15 @@ jobs:
- name: Setup LuaRocks
uses: leafo/gh-actions-luarocks@v6
- name: Install dependencies
- name: Install test dependencies
run: |
luarocks install busted
luarocks install lua-cjson
luarocks install luasocket
luarocks install pgmoon
luarocks install redis-lua
luarocks install luaossl
- name: Run API
run: |
cd devices-api
export DB_HOST=localhost DB_PORT=5432 DB_NAME=handheld_devices DB_USER=devices_user DB_PASSWORD=devices_password
export REDIS_HOST=localhost REDIS_PORT=6379
lua app-standalone.lua &
API_PID=$!
sleep 15
curl -f http://localhost:8080/health/ready || (kill $API_PID 2>/dev/null; exit 1)
curl -f http://localhost:8080/health/live || (kill $API_PID 2>/dev/null; exit 1)
kill $API_PID 2>/dev/null || true
- name: Run unit tests
run: make test
helm-lint:
name: Helm Lint

View File

@@ -1,9 +1,75 @@
.PHONY: generate
.PHONY: dev up down build test lint install-deps logs logs-api logs-worker logs-all \
init-db shell-postgres shell-api shell-worker status clean help
install-requirements:
brew install protobuf lua luarocks && luarocks install protobuf && luarocks install grpc
# Default target
help:
@echo "Handheld Devices - Makefile targets"
@echo ""
@echo " install-deps Install all deps for local dev (LuaRocks, Deno cache)"
@echo " dev, up Start all services (Postgres, Redis, API, worker, frontend)"
@echo " down Stop all services"
@echo " build Build Docker images"
@echo " test Run unit tests (devices-api)"
@echo " lint Run Luacheck and Deno check"
@echo ""
@echo " logs Follow API logs"
@echo " logs-worker Follow worker logs"
@echo " logs-all Follow all service logs"
@echo ""
@echo " init-db Run DB migrations (requires services up)"
@echo " shell-postgres Open psql in Postgres container"
@echo " shell-api Open shell in API container"
@echo " shell-worker Open shell in worker container"
@echo ""
@echo " status Show container status"
@echo " clean Stop and remove volumes"
verify-install:
protoc --version
lua -v
luarocks list | grep protobuf
install-deps:
luarocks install lua-cjson && luarocks install luasocket && luarocks install pgmoon && \
luarocks install redis-lua && luarocks install luaossl && luarocks install busted && \
luarocks install luacheck
cd frontend && deno cache main.ts
dev up:
docker-compose up -d
down:
docker-compose down
build:
docker-compose build
test:
$(MAKE) -C devices-api test
lint:
luacheck devices-api devices-worker --codes
cd frontend && deno check
logs:
docker-compose logs -f api
logs-worker:
docker-compose logs -f worker
logs-all:
docker-compose logs -f
init-db:
docker-compose exec postgres psql -U devices_user -d handheld_devices \
-f /docker-entrypoint-initdb.d/001_create_devices.sql
shell-postgres:
docker-compose exec postgres psql -U devices_user -d handheld_devices
shell-api:
docker-compose exec api sh
shell-worker:
docker-compose exec worker sh
status:
docker-compose ps
clean: down
docker-compose down -v

119
Readme.md
View File

@@ -0,0 +1,119 @@
# Handheld Devices
A microservices stack for managing handheld gaming device catalog data: Lua API and worker, Deno/Alpine.js frontend, PostgreSQL, and Redis.
## Architecture
| Service | Tech | Port | Description |
| -------- | ---------------- | ---- | -------------------------------- |
| API | Lua 5.4 | 8080 | REST API for devices CRUD |
| Worker | Lua 5.4 | - | Consumes events from Redis queue |
| Frontend | Deno + Alpine.js | 8090 | Web UI backed by Oak |
| Postgres | 15-alpine | 5432 | Primary data store |
| Redis | 7-alpine | 6379 | Event queue and caching |
## Quick Start
### Prerequisites
- Docker and Docker Compose
- Lua 5.4 + LuaRocks (for local dev/testing)
- Deno 2.x (for local frontend dev)
### Run with Docker Compose
```bash
cp .env.example .env
# Edit .env if needed (e.g. DB_PASSWORD)
make install-deps # optional: LuaRocks + Deno deps for local dev
make dev
```
- API: http://localhost:8080
- Frontend: http://localhost:8090
- Health: http://localhost:8080/health/ready
### Stop
```bash
make down
```
## Development
Install all dependencies for local development (LuaRocks packages and Deno cache):
```bash
make install-deps
```
### API (devices-api)
```bash
cd devices-api
make deps # luarocks install
make test # unit tests (busted)
make lint # luacheck
make run # run locally (needs Postgres + Redis)
```
### Worker (devices-worker)
```bash
cd devices-worker
make deps
make lint
make run # needs Postgres + Redis
```
### Frontend
```bash
cd frontend
make run # or: deno task start (with watch)
make lint # deno check
```
## Makefile Reference
From project root:
| Target | Description |
| --------------------- | ----------------------------------------- |
| `make install-deps` | Install LuaRocks + Deno deps for local dev |
| `make dev` | Start all services |
| `make down` | Stop all services |
| `make build` | Build Docker images |
| `make test` | Run API unit tests |
| `make lint` | Luacheck + Deno check |
| `make logs` | Follow API logs |
| `make logs-worker` | Follow worker logs |
| `make init-db` | Run DB migrations manually |
| `make shell-postgres` | psql in Postgres container |
| `make status` | Container status |
## API Endpoints
| Method | Path | Description |
| ------ | ------------- | ------------------------ |
| GET | /devices | List devices (paginated) |
| POST | /devices | Create device |
| GET | /devices/:id | Get device |
| PUT | /devices/:id | Update device |
| DELETE | /devices/:id | Delete device |
| GET | /health/ready | Readiness (DB + Redis) |
| GET | /health/live | Liveness |
## Deployment
- **Kubernetes**: `helm lint k8s/handheld-devices`
- **CI**: See `.github/workflows/ci.yml` (lint, build, unit tests, helm lint)
## Environment
See `.env.example` for configuration. Key variables:
- `DB_*` PostgreSQL connection
- `REDIS_*` Redis connection
- `API_URL` API URL used by the frontend (for browser requests)

5
devices-api/.busted Normal file
View File

@@ -0,0 +1,5 @@
return {
default = {
ROOT = { "spec" },
},
}

View File

@@ -1,39 +1,51 @@
.PHONY: init-db dev build clean logs down
.PHONY: run test lint deps init-db dev build logs logs-worker logs-all down shell-postgres shell-api shell-worker status
# Docker Compose: use parent dir's compose file (when run via make -C devices-api)
COMPOSE := docker-compose -f ../docker-compose.yml
run:
lua app-standalone.lua
test:
lua run_tests.lua
lint:
luacheck . --codes
deps:
luarocks install lua-cjson luasocket pgmoon redis-lua luaossl
# Docker Compose targets (run from project root: make -C devices-api <target>)
init-db:
docker-compose exec postgres psql -U devices_user -d handheld_devices -f /docker-entrypoint-initdb.d/001_create_devices.sql
$(COMPOSE) exec postgres psql -U devices_user -d handheld_devices \
-f /docker-entrypoint-initdb.d/001_create_devices.sql
dev up:
$(COMPOSE) up -d
build:
docker-compose build
dev:
docker-compose up -d
$(COMPOSE) build
logs:
docker-compose logs -f api
$(COMPOSE) logs -f api
logs-worker:
docker-compose logs -f worker
$(COMPOSE) logs -f worker
logs-all:
docker-compose logs -f
$(COMPOSE) logs -f
down:
docker-compose down
down-volumes:
docker-compose down -v
$(COMPOSE) down
shell-postgres:
docker-compose exec postgres psql -U devices_user -d handheld_devices
$(COMPOSE) exec postgres psql -U devices_user -d handheld_devices
shell-api:
docker-compose exec api sh
$(COMPOSE) exec api sh
shell-worker:
docker-compose exec worker sh
clean: down-volumes
$(COMPOSE) exec worker sh
status:
docker-compose ps
$(COMPOSE) ps

View File

@@ -0,0 +1,3 @@
#!/usr/bin/env lua
-- Busted test runner (uses .busted for ROOT = spec)
require("busted.runner")()

View File

@@ -0,0 +1,36 @@
describe("db", function()
local db
before_each(function()
db = require("db")
end)
describe("config", function()
it("has required connection fields", function()
assert.is_table(db.config)
assert.is_string(db.config.host)
assert.is_string(db.config.port)
assert.is_string(db.config.database)
assert.is_string(db.config.user)
assert.is_string(db.config.password)
end)
end)
describe("with_retry", function()
it("returns result when function succeeds immediately", function()
local result, err = db.with_retry(function()
return "ok"
end)
assert.are.equal("ok", result)
assert.is_nil(err)
end)
it("returns nil, err when function fails with non-retryable error", function()
local result, err = db.with_retry(function()
return nil, "validation failed"
end)
assert.is_nil(result)
assert.are.equal("validation failed", err)
end)
end)
end)

View File

@@ -0,0 +1,19 @@
describe("log", function()
local log
before_each(function()
log = require("log")
end)
it("exposes info, warn, error functions", function()
assert.is_function(log.info)
assert.is_function(log.warn)
assert.is_function(log.error)
end)
it("calls info without error", function()
assert.has_no.errors(function()
log.info("test message", { component = "test" })
end)
end)
end)

View File

@@ -1,4 +1,10 @@
.PHONY: run
.PHONY: run test lint deps
run:
lua worker.lua
lint:
luacheck . --codes
deps:
luarocks install lua-cjson luasocket pgmoon redis-lua

View File

@@ -1,7 +1,13 @@
.PHONY: run build
build:
docker build -t frontend-alpinejs .
.PHONY: run build dev start lint
run:
docker run -p 8090:8090 frontend-alpinejs
deno run --allow-net --allow-read --allow-write --allow-env --allow-run main.ts
start:
deno task start
build:
docker build -t handheld-devices-frontend .
lint:
deno check main.ts