mirror of
https://github.com/morbalint/kemkas-backend.git
synced 2026-07-17 21:23:46 +00:00
add e2e tests (#48)
* add e2e tests * oopsie * add docker compose file * add e2e nginx config * fix file location * add cert generation script and print logs for failure
This commit is contained in:
+88
-27
@@ -5,28 +5,60 @@ on:
|
|||||||
branches: [ "dev" ]
|
branches: [ "dev" ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "dev" ]
|
branches: [ "dev" ]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
frontend_image:
|
||||||
|
description: 'Frontend image to use in E2E tests (optional)'
|
||||||
|
required: false
|
||||||
|
default: 'ghcr.io/morbalint/kemkas-frontend:latest'
|
||||||
|
e2e_image:
|
||||||
|
description: 'E2E image to use in E2E tests (optional)'
|
||||||
|
required: false
|
||||||
|
default: 'ghcr.io/morbalint/kemkas-frontend:latest'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
docker-be-build:
|
test-and-build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
|
attestations: write
|
||||||
|
id-token: write
|
||||||
|
outputs:
|
||||||
|
image_sha_tag: ${{ steps.image-tag.outputs.image_sha_tag }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
- uses: actions/setup-dotnet@v4
|
- uses: actions/setup-dotnet@v5
|
||||||
with:
|
with:
|
||||||
dotnet-version: 10.0.x
|
dotnet-version: 10.0.x
|
||||||
- name: Run unit tests
|
- name: Run unit tests
|
||||||
run: dotnet test Kemkas.slnx -c Release
|
run: dotnet test Kemkas.slnx -c Release
|
||||||
- uses: docker/setup-buildx-action@v3
|
- uses: docker/setup-buildx-action@v4
|
||||||
- name: Log in to GitHub Container Registry
|
- name: Log in to GitHub Container Registry
|
||||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
uses: docker/login-action@v4
|
||||||
- run: |
|
with:
|
||||||
echo "GITHUB_SHA_SHORT=$(echo ${GITHUB_SHA::8})" >> $GITHUB_ENV
|
registry: ghcr.io
|
||||||
echo "registry.digitalocean.com/kemkas/kemkas-be:${GITHUB_SHA::8}"
|
username: ${{ github.actor }}
|
||||||
echo "ghcr.io/${{ github.repository_owner }}/kemkas-backend:${GITHUB_SHA::8}"
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- uses: docker/build-push-action@v5
|
- name: Compute image tag
|
||||||
|
id: image-tag
|
||||||
|
run: |
|
||||||
|
image_repo="ghcr.io/${{ github.repository_owner }}/kemkas-backend"
|
||||||
|
sha_tag="${image_repo}:${GITHUB_SHA::8}"
|
||||||
|
|
||||||
|
tags="$sha_tag"
|
||||||
|
if [[ "${GITHUB_REF}" == "refs/heads/main" ]]; then
|
||||||
|
tags+=$'\n'"${image_repo}:latest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "image_sha_tag=${sha_tag}" >> "$GITHUB_OUTPUT"
|
||||||
|
{
|
||||||
|
echo "tags<<EOF"
|
||||||
|
echo "$tags"
|
||||||
|
echo "EOF"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
- uses: docker/build-push-action@v7
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: Kemkas.Web/Dockerfile
|
file: Kemkas.Web/Dockerfile
|
||||||
@@ -35,21 +67,50 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
load: true
|
load: true
|
||||||
tags: |
|
tags: |
|
||||||
ghcr.io/${{ github.repository_owner }}/kemkas-backend:${{ env.GITHUB_SHA_SHORT }}
|
${{ steps.image-tag.outputs.tags }}
|
||||||
|
|
||||||
# - uses: actions/checkout@v4
|
e2e:
|
||||||
# with:
|
runs-on: ubuntu-latest
|
||||||
# repository: ${{ github.repository_owner }}/kemkas-deployment
|
needs:
|
||||||
# ref: refs/heads/main
|
- test-and-build
|
||||||
# path: ./deployment-repo
|
permissions:
|
||||||
# clean: false
|
contents: read
|
||||||
# ssh-key: ${{ secrets.DEPLOYMENT_REPO_DEPLOY_KEY }}
|
packages: read
|
||||||
# - uses: mikefarah/yq@v4
|
env:
|
||||||
# with:
|
BACKEND_IMAGE: ${{ needs.test-and-build.outputs.image_sha_tag }}
|
||||||
# cmd: yq -i '.spec.template.spec.containers[0].image = "registry.digitalocean.com/kemkas/kemkas-be:${{ env.GITHUB_SHA_SHORT }}"' ./deployment-repo/kemkas-beta/kemkas-be-deployment.yaml
|
FRONTEND_IMAGE: ${{ github.event.inputs.frontend_image || 'ghcr.io/morbalint/kemkas-frontend:latest' }}
|
||||||
# - run: |
|
E2E_IMAGE: ${{ github.event.inputs.e2e_image || 'ghcr.io/morbalint/kemkas-e2e:latest' }}
|
||||||
# cd ./deployment-repo
|
steps:
|
||||||
# git config --add user.email "deployment-bot@kemkas.hu"
|
- uses: actions/checkout@v6
|
||||||
# git config --add user.name "Deployment Bot"
|
- name: Log in to GitHub Container Registry
|
||||||
# git commit -a -m "deploy registry.digitalocean.com/kemkas/kemkas-be:${{ env.GITHUB_SHA_SHORT }}"
|
uses: docker/login-action@v4
|
||||||
# git push
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Setup docker compose
|
||||||
|
uses: docker/setup-compose-action@v2
|
||||||
|
- name: Pull images for test run
|
||||||
|
run: docker compose -f e2e.docker-compose.yaml pull
|
||||||
|
- name: Run Docker Compose E2E tests
|
||||||
|
run: docker compose -f e2e.docker-compose.yaml up --no-build --abort-on-container-exit --exit-code-from e2e e2e
|
||||||
|
- name: Print logs
|
||||||
|
if: failure()
|
||||||
|
run: docker compose -f e2e.docker-compose.yaml logs
|
||||||
|
- name: Upload Playwright HTML report
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: playwright-report
|
||||||
|
path: e2e/playwright-report
|
||||||
|
if-no-files-found: ignore
|
||||||
|
- name: Upload Playwright test results
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: playwright-test-results
|
||||||
|
path: e2e/test-results
|
||||||
|
if-no-files-found: ignore
|
||||||
|
- name: Tear down Docker Compose stack
|
||||||
|
if: always()
|
||||||
|
run: docker compose -f e2e.docker-compose.yaml down -v --remove-orphans
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ yarn-error.log*
|
|||||||
/tmp
|
/tmp
|
||||||
/temp
|
/temp
|
||||||
/local
|
/local
|
||||||
|
/e2e/
|
||||||
|
|
||||||
obj/
|
obj/
|
||||||
bin/
|
bin/
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
<File Path=".dockerignore" />
|
<File Path=".dockerignore" />
|
||||||
<File Path=".github/dependabot.yml" />
|
<File Path=".github/dependabot.yml" />
|
||||||
<File Path=".github/workflows/ci.yml" />
|
<File Path=".github/workflows/ci.yml" />
|
||||||
|
<File Path=".github/workflows/e2e.nginx.conf" />
|
||||||
<File Path=".gitignore" />
|
<File Path=".gitignore" />
|
||||||
<File Path="Kemkas.Web/docker-compose.yaml" />
|
<File Path="Kemkas.Web/docker-compose.yaml" />
|
||||||
<File Path="Kemkas.Web/nginx.conf" />
|
<File Path="Kemkas.Web/nginx.conf" />
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
services:
|
||||||
|
certs:
|
||||||
|
image: alpine:3.21
|
||||||
|
volumes:
|
||||||
|
- tls-certs:/certs
|
||||||
|
- ./scripts/generate-e2e-certs.sh:/scripts/generate-e2e-certs.sh:ro
|
||||||
|
command: ["sh", "/scripts/generate-e2e-certs.sh"]
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:16.13-alpine3.23
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: "kemkas"
|
||||||
|
POSTGRES_PASSWORD: "kemkas-dev42"
|
||||||
|
volumes:
|
||||||
|
- db-data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U kemkas -d postgres"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 20
|
||||||
|
start_period: 5s
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image: ${BACKEND_IMAGE:-ghcr.io/morbalint/kemkas-backend:b8565f8e}
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Kemkas.Web/Dockerfile
|
||||||
|
environment:
|
||||||
|
ConnectionStrings__DefaultConnection: "Server=db;User Id=kemkas;Password=kemkas-dev42"
|
||||||
|
Email__DomainName: "mail.kemkas.hu"
|
||||||
|
Email__ApiKey: ""
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image: ${FRONTEND_IMAGE:-ghcr.io/morbalint/kemkas-frontend:latest}
|
||||||
|
|
||||||
|
proxy:
|
||||||
|
image: nginx:1.29.7-alpine3.23
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
volumes:
|
||||||
|
- ./e2e.nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- tls-certs:/etc/nginx/certs:ro
|
||||||
|
depends_on:
|
||||||
|
certs:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
backend:
|
||||||
|
condition: service_started
|
||||||
|
frontend:
|
||||||
|
condition: service_started
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "wget -q --spider --no-check-certificate https://127.0.0.1:8000 || exit 1"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 20
|
||||||
|
start_period: 5s
|
||||||
|
|
||||||
|
e2e:
|
||||||
|
image: ${E2E_IMAGE:-ghcr.io/morbalint/kemkas-e2e:latest}
|
||||||
|
environment:
|
||||||
|
E2E_BASE_URL: https://proxy:8000
|
||||||
|
E2E_USE_WEBSERVER: "false"
|
||||||
|
E2E_TRUSTED_CERT_PATH: /certs/rootCA.pem
|
||||||
|
E2E_WAIT_FOR_URL: https://proxy:8000
|
||||||
|
volumes:
|
||||||
|
- tls-certs:/certs:ro
|
||||||
|
- ./e2e/playwright-report:/work/playwright-report
|
||||||
|
- ./e2e/test-results:/work/test-results
|
||||||
|
depends_on:
|
||||||
|
certs:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
proxy:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db-data:
|
||||||
|
tls-certs:
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
user nginx;
|
||||||
|
worker_processes auto;
|
||||||
|
|
||||||
|
error_log /var/log/nginx/error.log notice;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
|
access_log /var/log/nginx/access.log main;
|
||||||
|
|
||||||
|
sendfile on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
upstream frontend {
|
||||||
|
server frontend:80;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream backend {
|
||||||
|
server backend:8080;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 8000 ssl;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
ssl_certificate /etc/nginx/certs/kemkas.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/certs/kemkas.key;
|
||||||
|
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://frontend;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
location = /50x.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /Identity/ {
|
||||||
|
proxy_pass_request_headers on;
|
||||||
|
proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
|
||||||
|
proxy_set_header X-Forwarded-Proto "$scheme";
|
||||||
|
proxy_set_header X-Forwarded-Host "$http_host";
|
||||||
|
proxy_pass http://backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass_request_headers on;
|
||||||
|
proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
|
||||||
|
proxy_set_header X-Forwarded-Proto "$scheme";
|
||||||
|
proxy_set_header X-Forwarded-Host "$http_host";
|
||||||
|
proxy_pass http://backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /signin- {
|
||||||
|
proxy_pass_request_headers on;
|
||||||
|
proxy_set_header X-Forwarded-For "$proxy_add_x_forwarded_for";
|
||||||
|
proxy_set_header X-Forwarded-Proto "$scheme";
|
||||||
|
proxy_set_header X-Forwarded-Host "$http_host";
|
||||||
|
proxy_pass http://backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /lib/ {
|
||||||
|
proxy_pass_request_headers on;
|
||||||
|
proxy_pass http://backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /js/ {
|
||||||
|
proxy_pass_request_headers on;
|
||||||
|
proxy_pass http://backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /css/ {
|
||||||
|
proxy_pass_request_headers on;
|
||||||
|
proxy_pass http://backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /img/ {
|
||||||
|
proxy_pass_request_headers on;
|
||||||
|
proxy_pass http://backend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
CERT_DIR="${CERT_DIR:-/certs}"
|
||||||
|
|
||||||
|
mkdir -p "$CERT_DIR"
|
||||||
|
|
||||||
|
if [ -f "$CERT_DIR/rootCA.pem" ] && [ -f "$CERT_DIR/rootCA.key" ] && [ -f "$CERT_DIR/kemkas.pem" ] && [ -f "$CERT_DIR/kemkas.key" ]; then
|
||||||
|
echo "Using existing TLS material from $CERT_DIR"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
apk add --no-cache openssl >/dev/null
|
||||||
|
|
||||||
|
cat > /tmp/kemkas-server.cnf <<'EOF'
|
||||||
|
[req]
|
||||||
|
default_bits = 2048
|
||||||
|
prompt = no
|
||||||
|
default_md = sha256
|
||||||
|
distinguished_name = dn
|
||||||
|
req_extensions = req_ext
|
||||||
|
|
||||||
|
[dn]
|
||||||
|
CN = localhost
|
||||||
|
|
||||||
|
[req_ext]
|
||||||
|
subjectAltName = @alt_names
|
||||||
|
keyUsage = digitalSignature, keyEncipherment
|
||||||
|
extendedKeyUsage = serverAuth
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
DNS.1 = localhost
|
||||||
|
DNS.2 = proxy
|
||||||
|
DNS.3 = host.docker.internal
|
||||||
|
IP.1 = 127.0.0.1
|
||||||
|
IP.2 = ::1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /tmp/kemkas-v3.ext <<'EOF'
|
||||||
|
authorityKeyIdentifier=keyid,issuer
|
||||||
|
basicConstraints=CA:FALSE
|
||||||
|
keyUsage=digitalSignature,keyEncipherment
|
||||||
|
extendedKeyUsage=serverAuth
|
||||||
|
subjectAltName=@alt_names
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
DNS.1=localhost
|
||||||
|
DNS.2=proxy
|
||||||
|
DNS.3=host.docker.internal
|
||||||
|
IP.1=127.0.0.1
|
||||||
|
IP.2=::1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
openssl genrsa -out "$CERT_DIR/rootCA.key" 2048
|
||||||
|
openssl req -x509 -new -nodes -key "$CERT_DIR/rootCA.key" -sha256 -days 3650 -subj "/CN=kemkas-local-root" -out "$CERT_DIR/rootCA.pem"
|
||||||
|
|
||||||
|
openssl genrsa -out "$CERT_DIR/kemkas.key" 2048
|
||||||
|
openssl req -new -key "$CERT_DIR/kemkas.key" -out /tmp/kemkas.csr -config /tmp/kemkas-server.cnf
|
||||||
|
openssl x509 -req -in /tmp/kemkas.csr -CA "$CERT_DIR/rootCA.pem" -CAkey "$CERT_DIR/rootCA.key" -CAcreateserial -out "$CERT_DIR/kemkas.pem" -days 825 -sha256 -extfile /tmp/kemkas-v3.ext
|
||||||
|
|
||||||
|
echo "Generated TLS CA and nginx certificate under $CERT_DIR"
|
||||||
Reference in New Issue
Block a user