Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
95f7d53
frontend unit+e2e tests
HardMax71 Dec 21, 2025
0eb35ca
deps fix + adding folders with frontend test results to gitignore
HardMax71 Dec 21, 2025
519b53b
sonarqube issue fix
HardMax71 Dec 21, 2025
07ed784
ci frontend tests fix
HardMax71 Dec 21, 2025
cc85475
tests fix
HardMax71 Dec 21, 2025
578efc3
ci timeouts added (gha - 60s/10s, local - 30s/5s)
HardMax71 Dec 21, 2025
6350033
ci fix:
HardMax71 Dec 21, 2025
6055069
env home fix in ci
HardMax71 Dec 21, 2025
a0a76e7
ci frontend e2e tests fixes
HardMax71 Dec 21, 2025
7d1abca
ci tests running in parallel (frontend+backend), fixing of e2e tests
HardMax71 Dec 21, 2025
18a29ee
ci
HardMax71 Dec 22, 2025
3750c6f
ci fixes
HardMax71 Dec 22, 2025
bb40048
base url fix + tests fix (rabbit hints)
HardMax71 Dec 22, 2025
3cbd7d7
ci more debug output
HardMax71 Dec 22, 2025
5921f94
ci more debug output
HardMax71 Dec 22, 2025
fa55c9c
error display page + fixes
HardMax71 Dec 22, 2025
9b21b39
ci playwright fixes
HardMax71 Dec 22, 2025
143214b
ci: removed debug step, added users seeding step
HardMax71 Dec 22, 2025
aa27742
seed users fix (reapplying password)
HardMax71 Dec 22, 2025
f6c1dd0
db name fixes (no more suffix)
HardMax71 Dec 22, 2025
38576de
error display fix + moved from project name to db name for database
HardMax71 Dec 22, 2025
e489ca9
env updates
HardMax71 Dec 22, 2025
74d915f
env updates
HardMax71 Dec 22, 2025
3114292
ci: now frontend and backend have completely separate flows
HardMax71 Dec 22, 2025
ed64629
k3s cert in ci
HardMax71 Dec 22, 2025
233b0db
test timeout increase
HardMax71 Dec 22, 2025
1d0eca6
readme small update
HardMax71 Dec 22, 2025
87925f0
added tests and docs about frontend testing
HardMax71 Dec 22, 2025
0b9726b
lowerd duplication in test files
HardMax71 Dec 22, 2025
23e4b54
small tests fixes
HardMax71 Dec 22, 2025
220e199
refactoring (parametrized tests + lowered duplication)
HardMax71 Dec 22, 2025
83bd322
small test fixes
HardMax71 Dec 22, 2025
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
55 changes: 55 additions & 0 deletions .github/actions/setup-ci-compose/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Setup CI Compose
description: Creates docker-compose.ci.yaml with CI-specific modifications

inputs:
kubeconfig-path:
description: Path to kubeconfig file for cert-generator mount
required: true

runs:
using: composite
steps:
- name: Install yq
shell: bash
run: |
sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.50.1/yq_linux_amd64
sudo chmod +x /usr/local/bin/yq

- name: Create CI compose configuration
shell: bash
env:
KUBECONFIG_PATH: ${{ inputs.kubeconfig-path }}
run: |
cp docker-compose.yaml docker-compose.ci.yaml

# Backend environment variables
yq eval '.services.backend.environment += ["TESTING=true"]' -i docker-compose.ci.yaml
yq eval '.services.backend.environment += ["MONGO_ROOT_USER=root"]' -i docker-compose.ci.yaml
yq eval '.services.backend.environment += ["MONGO_ROOT_PASSWORD=rootpassword"]' -i docker-compose.ci.yaml
yq eval '.services.backend.environment += ["OTEL_SDK_DISABLED=true"]' -i docker-compose.ci.yaml

# Remove hot-reload volume mounts (causes permission issues and slow rebuilds in CI)
yq eval '.services.backend.volumes = [.services.backend.volumes[] | select(. != "./backend:/app")]' -i docker-compose.ci.yaml
yq eval '.services."k8s-worker".volumes = [.services."k8s-worker".volumes[] | select(. != "./backend:/app:ro")]' -i docker-compose.ci.yaml
yq eval '.services."pod-monitor".volumes = [.services."pod-monitor".volumes[] | select(. != "./backend:/app:ro")]' -i docker-compose.ci.yaml
yq eval '.services."result-processor".volumes = [.services."result-processor".volumes[] | select(. != "./backend:/app:ro")]' -i docker-compose.ci.yaml
yq eval '.services.frontend.volumes = [.services.frontend.volumes[] | select(. != "./frontend:/app")]' -i docker-compose.ci.yaml

# Disable Kafka SASL authentication for CI
yq eval 'del(.services.kafka.environment.KAFKA_OPTS)' -i docker-compose.ci.yaml
yq eval 'del(.services.zookeeper.environment.KAFKA_OPTS)' -i docker-compose.ci.yaml
yq eval 'del(.services.zookeeper.environment.ZOOKEEPER_AUTH_PROVIDER_1)' -i docker-compose.ci.yaml
yq eval '.services.kafka.volumes = [.services.kafka.volumes[] | select(. | contains("jaas.conf") | not)]' -i docker-compose.ci.yaml
yq eval '.services.zookeeper.volumes = [.services.zookeeper.volumes[] | select(. | contains("/etc/kafka") | not)]' -i docker-compose.ci.yaml

# Simplify Zookeeper for CI
yq eval '.services.zookeeper.environment.ZOOKEEPER_4LW_COMMANDS_WHITELIST = "ruok,srvr"' -i docker-compose.ci.yaml
yq eval 'del(.services.zookeeper.healthcheck)' -i docker-compose.ci.yaml
yq eval '.services.kafka.depends_on.zookeeper.condition = "service_started"' -i docker-compose.ci.yaml

# Cert-generator CI configuration
yq eval '.services."cert-generator".extra_hosts = ((.services."cert-generator".extra_hosts // []) + ["host.docker.internal:host-gateway"] | unique)' -i docker-compose.ci.yaml
yq eval '.services."cert-generator".environment = ((.services."cert-generator".environment // []) + ["CI=true"] | unique)' -i docker-compose.ci.yaml
yq eval ".services.\"cert-generator\".volumes += [\"${KUBECONFIG_PATH}:/root/.kube/config:ro\"]" -i docker-compose.ci.yaml

echo "Created docker-compose.ci.yaml"
128 changes: 128 additions & 0 deletions .github/workflows/backend-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
name: Backend CI

on:
push:
branches: [main, dev]
paths:
- 'backend/**'
- '.github/workflows/backend-ci.yml'
- 'docker-compose.ci.yaml'
pull_request:
branches: [main, dev]
paths:
- 'backend/**'
- '.github/workflows/backend-ci.yml'
- 'docker-compose.ci.yaml'
workflow_dispatch:

jobs:
integration:
name: Integration Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: "backend/uv.lock"

- name: Install Python dependencies
run: |
cd backend
uv python install 3.12
uv sync --frozen

- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Setup Kubernetes (k3s)
run: |
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik --tls-san host.docker.internal" sh -
mkdir -p /home/runner/.kube
sudo k3s kubectl config view --raw > /home/runner/.kube/config
sudo chmod 600 /home/runner/.kube/config
export KUBECONFIG=/home/runner/.kube/config
timeout 90 bash -c 'until sudo k3s kubectl cluster-info; do sleep 5; done'

- name: Create kubeconfig for CI Docker containers
run: |
# Copy real k3s kubeconfig with valid credentials, but change server address
# from 127.0.0.1 to host.docker.internal for Docker container networking
# (k3s was started with --tls-san host.docker.internal so the cert is valid)
sed 's|https://127.0.0.1:6443|https://host.docker.internal:6443|g' \
/home/runner/.kube/config > backend/kubeconfig.yaml
chmod 644 backend/kubeconfig.yaml

- name: Setup CI Compose
uses: ./.github/actions/setup-ci-compose
with:
kubeconfig-path: /home/runner/.kube/config

- name: Build services
uses: docker/bake-action@v6
with:
source: .
files: docker-compose.ci.yaml
load: true
set: |
*.cache-from=type=gha,scope=buildkit-${{ github.repository }}-${{ github.ref_name }}
*.cache-from=type=gha,scope=buildkit-${{ github.repository }}-main
*.cache-to=type=gha,mode=max,scope=buildkit-${{ github.repository }}-${{ github.ref_name }}
*.pull=true
env:
BUILDKIT_PROGRESS: plain

- name: Start services
run: |
docker compose -f docker-compose.ci.yaml up -d --remove-orphans
docker compose -f docker-compose.ci.yaml ps

- name: Wait for backend
run: |
curl --retry 60 --retry-delay 5 --retry-all-errors -ksf https://127.0.0.1:443/api/v1/health/live
docker compose -f docker-compose.ci.yaml ps
kubectl get pods -A -o wide

- name: Run integration tests
timeout-minutes: 10
env:
BACKEND_BASE_URL: https://127.0.0.1:443
MONGO_ROOT_USER: root
MONGO_ROOT_PASSWORD: rootpassword
MONGODB_HOST: 127.0.0.1
MONGODB_PORT: 27017
MONGODB_URL: mongodb://root:[email protected]:27017/?authSource=admin
SCHEMA_SUBJECT_PREFIX: "ci.${{ github.run_id }}."
run: |
cd backend
uv run pytest tests/integration -v --cov=app --cov-branch --cov-report=xml --cov-report=term

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
if: always()
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: backend/coverage.xml
flags: backend
name: backend-coverage
slug: HardMax71/Integr8sCode
fail_ci_if_error: false

- name: Collect logs
if: failure()
run: |
mkdir -p logs
docker compose -f docker-compose.ci.yaml logs > logs/docker-compose.log
docker compose -f docker-compose.ci.yaml logs backend > logs/backend.log
docker compose -f docker-compose.ci.yaml logs mongo > logs/mongo.log
kubectl get events --sort-by='.metadata.creationTimestamp' > logs/k8s-events.log 2>&1 || true
kubectl describe pods -A > logs/k8s-describe-pods.log 2>&1 || true

- name: Upload logs
if: failure()
uses: actions/upload-artifact@v6
with:
name: backend-logs
path: logs/
167 changes: 167 additions & 0 deletions .github/workflows/frontend-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
name: Frontend CI

on:
push:
branches: [main, dev]
paths:
- 'frontend/**'
- '.github/workflows/frontend-ci.yml'
- 'docker-compose.ci.yaml'
pull_request:
branches: [main, dev]
paths:
- 'frontend/**'
- '.github/workflows/frontend-ci.yml'
- 'docker-compose.ci.yaml'
workflow_dispatch:

jobs:
unit:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
working-directory: frontend
run: npm ci

- name: Run unit tests with coverage
working-directory: frontend
run: npm run test:coverage

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: frontend/coverage/lcov.info
flags: frontend
name: frontend-coverage
slug: HardMax71/Integr8sCode
fail_ci_if_error: false

e2e:
name: E2E Tests
needs: unit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
working-directory: frontend
run: npm ci

- name: Install Playwright browsers
working-directory: frontend
run: npx playwright install chromium

- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Setup Kubernetes (k3s)
run: |
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik --tls-san host.docker.internal" sh -
mkdir -p /home/runner/.kube
sudo k3s kubectl config view --raw > /home/runner/.kube/config
sudo chmod 600 /home/runner/.kube/config
export KUBECONFIG=/home/runner/.kube/config
timeout 90 bash -c 'until sudo k3s kubectl cluster-info; do sleep 5; done'

- name: Create kubeconfig for CI
run: |
cat > backend/kubeconfig.yaml <<EOF
apiVersion: v1
kind: Config
clusters:
- name: ci-cluster
cluster:
server: https://host.docker.internal:6443
insecure-skip-tls-verify: true
users:
- name: ci-user
user:
token: "ci-token"
contexts:
- name: ci
context:
cluster: ci-cluster
user: ci-user
current-context: ci
EOF

- name: Setup CI Compose
uses: ./.github/actions/setup-ci-compose
with:
kubeconfig-path: /home/runner/.kube/config

- name: Build services
uses: docker/bake-action@v6
with:
source: .
files: docker-compose.ci.yaml
load: true
set: |
*.cache-from=type=gha,scope=buildkit-${{ github.repository }}-${{ github.ref_name }}
*.cache-from=type=gha,scope=buildkit-${{ github.repository }}-main
*.cache-to=type=gha,mode=max,scope=buildkit-${{ github.repository }}-${{ github.ref_name }}
*.pull=true
env:
BUILDKIT_PROGRESS: plain

- name: Start services
run: |
docker compose -f docker-compose.ci.yaml up -d --remove-orphans
docker compose -f docker-compose.ci.yaml ps

- name: Wait for services
run: |
echo "Waiting for backend..."
curl --retry 60 --retry-delay 5 --retry-all-errors -ksf https://127.0.0.1:443/api/v1/health/live
echo "Waiting for frontend..."
curl --retry 60 --retry-delay 5 --retry-all-errors -ksf https://127.0.0.1:5001/

- name: Seed test users
run: |
docker compose -f docker-compose.ci.yaml exec -T backend uv run python scripts/seed_users.py

- name: Run E2E tests
working-directory: frontend
env:
CI: true
run: npx playwright test --reporter=html

- name: Upload Playwright report
uses: actions/upload-artifact@v6
if: always()
with:
name: playwright-report
path: frontend/playwright-report/

- name: Collect logs
if: failure()
run: |
mkdir -p logs
docker compose -f docker-compose.ci.yaml logs > logs/docker-compose.log
docker compose -f docker-compose.ci.yaml logs backend > logs/backend.log
docker compose -f docker-compose.ci.yaml logs frontend > logs/frontend.log

- name: Upload logs
if: failure()
uses: actions/upload-artifact@v6
with:
name: frontend-e2e-logs
path: logs/
Loading
Loading