From 59ddc66a8ec9e7574c28ab24817a480f4ec51da8 Mon Sep 17 00:00:00 2001 From: Christian van Dijk Date: Mon, 23 Feb 2026 22:52:54 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=F0=9F=A7=B1=20add=20tests=20&=20ci=20?= =?UTF-8?q?changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 45 ++----------- Makefile | 80 +++++++++++++++++++++-- Readme.md | 119 ++++++++++++++++++++++++++++++++++ devices-api/.busted | 5 ++ devices-api/Makefile | 50 ++++++++------ devices-api/run_tests.lua | 3 + devices-api/spec/db_spec.lua | 36 ++++++++++ devices-api/spec/log_spec.lua | 19 ++++++ devices-worker/Makefile | 8 ++- frontend/Makefile | 16 +++-- 10 files changed, 309 insertions(+), 72 deletions(-) create mode 100644 devices-api/.busted create mode 100644 devices-api/run_tests.lua create mode 100644 devices-api/spec/db_spec.lua create mode 100644 devices-api/spec/log_spec.lua diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4cbe1c4..bb81309 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/Makefile b/Makefile index 706d609..e4c4d38 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/Readme.md b/Readme.md index e69de29..a77d1d2 100644 --- a/Readme.md +++ b/Readme.md @@ -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) diff --git a/devices-api/.busted b/devices-api/.busted new file mode 100644 index 0000000..68deb5c --- /dev/null +++ b/devices-api/.busted @@ -0,0 +1,5 @@ +return { + default = { + ROOT = { "spec" }, + }, +} diff --git a/devices-api/Makefile b/devices-api/Makefile index 4df2da1..80b6ea7 100644 --- a/devices-api/Makefile +++ b/devices-api/Makefile @@ -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 ) 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 diff --git a/devices-api/run_tests.lua b/devices-api/run_tests.lua new file mode 100644 index 0000000..59b9ac9 --- /dev/null +++ b/devices-api/run_tests.lua @@ -0,0 +1,3 @@ +#!/usr/bin/env lua +-- Busted test runner (uses .busted for ROOT = spec) +require("busted.runner")() diff --git a/devices-api/spec/db_spec.lua b/devices-api/spec/db_spec.lua new file mode 100644 index 0000000..2fe29f4 --- /dev/null +++ b/devices-api/spec/db_spec.lua @@ -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) diff --git a/devices-api/spec/log_spec.lua b/devices-api/spec/log_spec.lua new file mode 100644 index 0000000..fcecbd0 --- /dev/null +++ b/devices-api/spec/log_spec.lua @@ -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) diff --git a/devices-worker/Makefile b/devices-worker/Makefile index e8e0bd5..3099d16 100644 --- a/devices-worker/Makefile +++ b/devices-worker/Makefile @@ -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 diff --git a/frontend/Makefile b/frontend/Makefile index 68ad2b3..7c97829 100644 --- a/frontend/Makefile +++ b/frontend/Makefile @@ -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