Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
73 changes: 73 additions & 0 deletions .github/workflows/api-coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: API Service Coverage

on:
push:
branches: ["main"]
paths:
- "api/**"
pull_request:
paths:
- "api/**"

defaults:
run:
working-directory: api

jobs:
unit-tests-with-coverage:
name: Unit tests + coverage enforcement
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: api/package-lock.json

- name: Install dependencies
run: npm ci

- name: Run tests with V8 coverage
run: npm run test:coverage

- name: Upload coverage report
uses: actions/upload-artifact@v4
if: always()
with:
name: api-coverage
path: api/coverage/

- name: Publish coverage to PR summary
if: always()
run: |
echo "## API Service Coverage Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f coverage/coverage-summary.json ]; then
node -e "
const fs = require('fs');
const summary = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8'));
const total = summary.total;
const thresholds = { lines: 80, branches: 75, functions: 80, statements: 80 };
let failed = false;
const rows = [];
for (const [key, threshold] of Object.entries(thresholds)) {
const pct = total[key]?.pct ?? 0;
const pass = pct >= threshold;
if (!pass) failed = true;
rows.push(\`| \${key} | \${pct.toFixed(1)}% | \${threshold}% | \${pass ? '✅' : '❌'} |\`);
}
const table = [
'| Metric | Actual | Threshold | Status |',
'|--------|--------|-----------|--------|',
...rows,
].join('\n');
fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, table + '\n');
if (failed) process.exit(1);
"
else
echo "Coverage report not found." >> $GITHUB_STEP_SUMMARY
exit 1
fi
92 changes: 92 additions & 0 deletions .github/workflows/frontend-snapshot-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
name: Frontend Snapshot Tests

on:
push:
branches: ["main"]
paths:
- "frontend/**"
pull_request:
paths:
- "frontend/**"

defaults:
run:
working-directory: frontend

jobs:
snapshot-tests:
name: Vitest snapshot tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
run: npm ci

- name: Run snapshot tests with coverage
run: npm run test:coverage

- name: Upload coverage report
uses: actions/upload-artifact@v4
if: always()
with:
name: frontend-coverage
path: frontend/coverage/

- name: Publish coverage summary
if: always()
run: |
if [ -f coverage/coverage-summary.json ]; then
echo "## Frontend Coverage" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
npx c8 report --reporter=text 2>/dev/null || cat coverage/coverage-summary.json | \
node -e "
const d = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).total;
console.log('Lines: ' + d.lines.pct + '%');
console.log('Branches: ' + d.branches.pct + '%');
console.log('Functions: ' + d.functions.pct + '%');
console.log('Statements:' + d.statements.pct + '%');
"
echo '```' >> $GITHUB_STEP_SUMMARY
fi

- name: Fail on outdated snapshots
run: |
# Re-run with --update-snapshots dry-run; fail if any snapshot would change.
npx vitest run --reporter=verbose 2>&1 | tee /tmp/vitest-out.txt
if grep -q "obsolete snapshot" /tmp/vitest-out.txt; then
echo "Obsolete snapshots detected. Run: npm run test:snapshot:update" >&2
exit 1
fi

storybook-build:
name: Storybook build check
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
run: npm ci

- name: Build Storybook
run: npm run build-storybook

- name: Upload Storybook build
uses: actions/upload-artifact@v4
with:
name: storybook-static
path: frontend/storybook-static/
84 changes: 84 additions & 0 deletions .github/workflows/sep24-integration-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: SEP-24 Integration Tests (Nightly)

on:
schedule:
# Run nightly at 02:00 UTC
- cron: "0 2 * * *"
workflow_dispatch:
inputs:
anchor_version:
description: "Anchor Platform Docker image tag"
required: false
default: "3.0.0"

defaults:
run:
working-directory: api

env:
ANCHOR_PLATFORM_URL: http://localhost:8080
TEST_ASSET_CODE: USDC
TEST_ASSET_ISSUER: GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5
TEST_STELLAR_ACCOUNT: GABC1234DEF5678HIJK9012LMNO3456PQRS7890TUVW1234XYZ5678ABCD

jobs:
sep24-integration:
name: SEP-24 deposit flow — happy path + expiry + refund
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: api/package-lock.json

- name: Install dependencies
run: npm ci

- name: Start Anchor Platform via Docker Compose
working-directory: tests/docker
run: |
docker compose -f sep24-docker-compose.yml up -d
echo "Waiting for Anchor Platform to be healthy..."
timeout 90 bash -c 'until curl -sf http://localhost:8080/health; do sleep 3; done'
echo "Anchor Platform is ready."

- name: Obtain SEP-10 JWT for test account
id: sep10
run: |
# Fetch the challenge transaction from the anchor
CHALLENGE=$(curl -sf "http://localhost:8080/auth?account=${TEST_STELLAR_ACCOUNT}" | jq -r .transaction)
# In a real setup you would sign with the test account's private key.
# For CI we use the Anchor Platform's test-mode which accepts unsigned challenges.
TOKEN=$(curl -sf -X POST http://localhost:8080/auth \
-H "Content-Type: application/json" \
-d "{\"transaction\": \"${CHALLENGE}\"}" | jq -r .token)
echo "SEP10_JWT=${TOKEN}" >> $GITHUB_ENV

- name: Run SEP-24 integration tests
env:
SEP10_JWT: ${{ env.SEP10_JWT }}
run: npm run test:integration

- name: Collect Docker logs on failure
if: failure()
working-directory: tests/docker
run: docker compose -f sep24-docker-compose.yml logs --no-color

- name: Tear down Anchor Platform
if: always()
working-directory: tests/docker
run: docker compose -f sep24-docker-compose.yml down -v

- name: Publish test results summary
if: always()
run: |
echo "## SEP-24 Integration Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- Anchor Platform: ${{ github.event.inputs.anchor_version || '3.0.0' }}" >> $GITHUB_STEP_SUMMARY
echo "- Network: TESTNET" >> $GITHUB_STEP_SUMMARY
echo "- Run at: $(date -u)" >> $GITHUB_STEP_SUMMARY
81 changes: 81 additions & 0 deletions .github/workflows/webhook-chaos-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Webhook Chaos Tests

on:
schedule:
# Run nightly at 03:00 UTC alongside SEP-24 integration suite
- cron: "0 3 * * *"
workflow_dispatch:

defaults:
run:
working-directory: api

env:
TOXIPROXY_URL: http://localhost:8474
WEBHOOK_PROXY_PORT: "9090"
WEBHOOK_TARGET_URL: http://localhost:3001

jobs:
webhook-chaos:
name: Chaos tests — latency, reset, timeout, DLQ
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: api/package-lock.json

- name: Install dependencies
run: npm ci

- name: Start Toxiproxy + webhook echo server
working-directory: tests/docker
run: |
docker compose -f chaos-docker-compose.yml up -d
echo "Waiting for Toxiproxy..."
timeout 60 bash -c 'until curl -sf http://localhost:8474/proxies; do sleep 2; done'
echo "Waiting for echo server..."
timeout 30 bash -c 'until curl -sf http://localhost:3001/health; do sleep 2; done'
echo "Infrastructure ready."

- name: Create Toxiproxy webhook proxy
run: |
curl -sf -X POST http://localhost:8474/proxies \
-H "Content-Type: application/json" \
-d '{
"name": "webhook-target",
"listen": "0.0.0.0:9090",
"upstream": "webhook-echo:3001",
"enabled": true
}'

- name: Run chaos tests
run: npm run test:chaos

- name: Collect infrastructure logs on failure
if: failure()
working-directory: tests/docker
run: docker compose -f chaos-docker-compose.yml logs --no-color

- name: Tear down infrastructure
if: always()
working-directory: tests/docker
run: docker compose -f chaos-docker-compose.yml down -v

- name: Publish chaos test summary
if: always()
run: |
echo "## Webhook Chaos Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Fault | Expected behaviour |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------------------|" >> $GITHUB_STEP_SUMMARY
echo "| No fault (baseline) | Delivers on first attempt |" >> $GITHUB_STEP_SUMMARY
echo "| +1 s latency | Delivers within timeout |" >> $GITHUB_STEP_SUMMARY
echo "| Connection reset | Retries → DLQ after max retries |" >> $GITHUB_STEP_SUMMARY
echo "| 30 s timeout | Timeout fires → DLQ after max retries |" >> $GITHUB_STEP_SUMMARY
echo "| Exponential backoff | Delays grow monotonically |" >> $GITHUB_STEP_SUMMARY
Loading
Loading