✅🧱 add tests & ci changes
This commit is contained in:
45
.github/workflows/ci.yml
vendored
45
.github/workflows/ci.yml
vendored
@@ -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
|
||||
|
||||
80
Makefile
80
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
|
||||
|
||||
119
Readme.md
119
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)
|
||||
|
||||
5
devices-api/.busted
Normal file
5
devices-api/.busted
Normal file
@@ -0,0 +1,5 @@
|
||||
return {
|
||||
default = {
|
||||
ROOT = { "spec" },
|
||||
},
|
||||
}
|
||||
@@ -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
|
||||
|
||||
3
devices-api/run_tests.lua
Normal file
3
devices-api/run_tests.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env lua
|
||||
-- Busted test runner (uses .busted for ROOT = spec)
|
||||
require("busted.runner")()
|
||||
36
devices-api/spec/db_spec.lua
Normal file
36
devices-api/spec/db_spec.lua
Normal 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)
|
||||
19
devices-api/spec/log_spec.lua
Normal file
19
devices-api/spec/log_spec.lua
Normal 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)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user