test(api): add API test on contacts
next will be to add CI on it
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
# API functional tests
|
||||
|
||||
Tests are written using [Hurl](https://hurl.dev) — a plain-text, CLI-first HTTP testing tool.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [Hurl](https://hurl.dev/docs/installation.html) ≥ 4.0
|
||||
Install: `cargo install hurl` or via your package manager
|
||||
|
||||
## Configuration
|
||||
|
||||
Edit `.env` to match your local instance. This file is the single source of
|
||||
truth: `run.sh` sources it for shell variables and passes it to Hurl as
|
||||
`--variables-file`.
|
||||
|
||||
```
|
||||
base_url=http://localhost:8087
|
||||
username=admin
|
||||
email=admin@example.com
|
||||
password=TestPassword1!
|
||||
```
|
||||
|
||||
## Running the tests
|
||||
|
||||
```bash
|
||||
# First-time setup (run once on a fresh instance)
|
||||
hurl --variables-file tests/api/hurl.vars --test tests/api/setup.hurl
|
||||
|
||||
# Contacts CRUD scenario
|
||||
hurl --variables-file tests/api/hurl.vars --test tests/api/contacts.hurl
|
||||
|
||||
# All scenarios at once
|
||||
hurl --variables-file tests/api/hurl.vars --test tests/api/setup.hurl tests/api/contacts.hurl
|
||||
|
||||
# With full request/response output
|
||||
hurl --variables-file tests/api/hurl.vars --test --verbose tests/api/contacts.hurl
|
||||
|
||||
# Generate an HTML report
|
||||
hurl --variables-file tests/api/hurl.vars --test --report-html /tmp/hurl-report tests/api/contacts.hurl
|
||||
```
|
||||
|
||||
## Test files
|
||||
|
||||
| File | Description |
|
||||
|---|---|
|
||||
| `setup.hurl` | One-time admin account creation; also asserts the endpoint is locked afterwards |
|
||||
| `contacts.hurl` | Full contacts CRUD scenario (13 steps, see below) |
|
||||
| `.env` | Variables: `base_url`, `username`, `email`, `password` — used by both Hurl and `run.sh` |
|
||||
|
||||
## Scenario: `contacts.hurl`
|
||||
|
||||
| Step | Description |
|
||||
|---|---|
|
||||
| 1 | Login – capture JWT token |
|
||||
| 2 | List address books – assert system book is present and read-only |
|
||||
| 3 | Create personal address book – capture `book_id` |
|
||||
| 4 | List contacts in new book – assert empty |
|
||||
| 5 | Create contact John Doe – capture `contact_id` |
|
||||
| 6 | List contacts – assert exactly 1 result with John Doe's id |
|
||||
| 7 | Get John Doe – assert all fields, capture `ETag` |
|
||||
| 8 | Update John Doe (nickname, org, notes) with `If-Match` – assert new values, capture refreshed `ETag` |
|
||||
| 9 | Delete John Doe with `If-Match` |
|
||||
| 10 | List contacts – assert empty again |
|
||||
| 11 | Delete personal address book |
|
||||
| 12 | List address books – assert `book_id` no longer present |
|
||||
| 13 | List system address book – assert non-empty collection of OxiCloud users |
|
||||
|
||||
## Legacy bash tests
|
||||
|
||||
`test.sh` and `common.sh` are the original curl/bash scripts kept for reference.
|
||||
Run them with `bash tests/api/test.sh` from the repo root (requires `jq`).
|
||||
@@ -0,0 +1,258 @@
|
||||
# =============================================================
|
||||
# OxiCloud – Contacts API end-to-end scenario
|
||||
# =============================================================
|
||||
# Run:
|
||||
# hurl --variables-file tests/api/hurl.vars --test tests/api/contacts.hurl
|
||||
#
|
||||
# Variables required (see hurl.vars):
|
||||
# base_url – e.g. http://localhost:8087
|
||||
# username – OxiCloud username
|
||||
# password – OxiCloud password
|
||||
# =============================================================
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 1 – Login and capture the JWT token
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
POST {{base_url}}/api/auth/login
|
||||
Content-Type: application/json
|
||||
{
|
||||
"username": "{{username}}",
|
||||
"password": "{{password}}"
|
||||
}
|
||||
|
||||
HTTP 200
|
||||
[Captures]
|
||||
token: jsonpath "$.access_token"
|
||||
[Asserts]
|
||||
jsonpath "$.access_token" isString
|
||||
jsonpath "$.token_type" == "Bearer"
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 2 – List address books (at least the system book)
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
GET {{base_url}}/api/address-books
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$" isCollection
|
||||
# System address book must always be present
|
||||
jsonpath "$[?(@.id == 'system')].is_system" == true
|
||||
jsonpath "$[?(@.id == 'system')].is_readonly" == true
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 3 – Create a personal address book
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
POST {{base_url}}/api/address-books
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
{
|
||||
"name": "Personal",
|
||||
"description": "Personal address book created by Hurl tests",
|
||||
"is_public": false
|
||||
}
|
||||
|
||||
HTTP 201
|
||||
[Captures]
|
||||
book_id: jsonpath "$.id"
|
||||
[Asserts]
|
||||
jsonpath "$.id" isString
|
||||
jsonpath "$.name" == "Personal"
|
||||
jsonpath "$.description" == "Personal address book created by Hurl tests"
|
||||
jsonpath "$.is_public" == false
|
||||
jsonpath "$.is_system" == false
|
||||
jsonpath "$.is_readonly" == false
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 4 – List contacts in the new book – must be empty
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
GET {{base_url}}/api/address-books/{{book_id}}/contacts
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$" isCollection
|
||||
jsonpath "$" count == 0
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 5 – Create contact John Doe
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
POST {{base_url}}/api/address-books/{{book_id}}/contacts
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
{
|
||||
"first_name": "John",
|
||||
"last_name": "Doe",
|
||||
"full_name": "John Doe",
|
||||
"email": [
|
||||
{
|
||||
"email": "john.doe@example.com",
|
||||
"type": "work",
|
||||
"is_primary": true
|
||||
}
|
||||
],
|
||||
"phone": [
|
||||
{
|
||||
"number": "+1-555-0100",
|
||||
"type": "mobile",
|
||||
"is_primary": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
HTTP 201
|
||||
[Captures]
|
||||
contact_id: jsonpath "$.id"
|
||||
[Asserts]
|
||||
jsonpath "$.id" isString
|
||||
jsonpath "$.address_book_id" == {{book_id}}
|
||||
jsonpath "$.first_name" == "John"
|
||||
jsonpath "$.last_name" == "Doe"
|
||||
jsonpath "$.full_name" == "John Doe"
|
||||
jsonpath "$.email" count == 1
|
||||
jsonpath "$.email[0].email" == "john.doe@example.com"
|
||||
jsonpath "$.email[0].type" == "work"
|
||||
jsonpath "$.email[0].is_primary" == true
|
||||
jsonpath "$.phone" count == 1
|
||||
jsonpath "$.phone[0].number" == "+1-555-0100"
|
||||
jsonpath "$.phone[0].type" == "mobile"
|
||||
jsonpath "$.phone[0].is_primary" == true
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 6 – List contacts – exactly 1 result, must be John Doe
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
GET {{base_url}}/api/address-books/{{book_id}}/contacts
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$" count == 1
|
||||
jsonpath "$[*].id" contains {{contact_id}}
|
||||
jsonpath "$[0].first_name" == "John"
|
||||
jsonpath "$[0].last_name" == "Doe"
|
||||
jsonpath "$[0].full_name" == "John Doe"
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 7 – Get John Doe by id and verify all fields
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
GET {{base_url}}/api/address-books/{{book_id}}/contacts/{{contact_id}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
HTTP 200
|
||||
[Captures]
|
||||
etag: header "ETag"
|
||||
[Asserts]
|
||||
header "ETag" exists
|
||||
jsonpath "$.id" == {{contact_id}}
|
||||
jsonpath "$.address_book_id" == {{book_id}}
|
||||
jsonpath "$.first_name" == "John"
|
||||
jsonpath "$.last_name" == "Doe"
|
||||
jsonpath "$.full_name" == "John Doe"
|
||||
jsonpath "$.email[0].email" == "john.doe@example.com"
|
||||
jsonpath "$.email[0].type" == "work"
|
||||
jsonpath "$.email[0].is_primary" == true
|
||||
jsonpath "$.phone[0].number" == "+1-555-0100"
|
||||
jsonpath "$.phone[0].type" == "mobile"
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 8 – Update John Doe: add nickname, notes, and organisation
|
||||
# Uses If-Match for optimistic concurrency
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
PUT {{base_url}}/api/address-books/{{book_id}}/contacts/{{contact_id}}
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
If-Match: {{etag}}
|
||||
{
|
||||
"first_name": "John",
|
||||
"last_name": "Doe",
|
||||
"full_name": "John Doe",
|
||||
"nickname": "JD",
|
||||
"organization": "ACME Corp",
|
||||
"notes": "Updated via Hurl test",
|
||||
"email": [
|
||||
{
|
||||
"email": "john.doe@example.com",
|
||||
"type": "work",
|
||||
"is_primary": true
|
||||
}
|
||||
],
|
||||
"phone": [
|
||||
{
|
||||
"number": "+1-555-0100",
|
||||
"type": "mobile",
|
||||
"is_primary": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
HTTP 200
|
||||
[Captures]
|
||||
etag: header "ETag"
|
||||
[Asserts]
|
||||
header "ETag" exists
|
||||
jsonpath "$.id" == {{contact_id}}
|
||||
jsonpath "$.first_name" == "John"
|
||||
jsonpath "$.last_name" == "Doe"
|
||||
jsonpath "$.nickname" == "JD"
|
||||
jsonpath "$.organization" == "ACME Corp"
|
||||
jsonpath "$.notes" == "Updated via Hurl test"
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 9 – Delete John Doe (uses refreshed ETag from step 8)
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
DELETE {{base_url}}/api/address-books/{{book_id}}/contacts/{{contact_id}}
|
||||
Authorization: Bearer {{token}}
|
||||
If-Match: {{etag}}
|
||||
|
||||
HTTP 204
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 10 – Address book must be empty again
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
GET {{base_url}}/api/address-books/{{book_id}}/contacts
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$" count == 0
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 11 – Delete the personal address book
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
DELETE {{base_url}}/api/address-books/{{book_id}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
HTTP 204
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 12 – Verify the address book is gone from the list
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
GET {{base_url}}/api/address-books
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$[*].id" not contains {{book_id}}
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 13 – List the system address book (OxiCloud users)
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
GET {{base_url}}/api/address-books/system/contacts
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$" isCollection
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env bash
|
||||
# Full Hurl API test runner.
|
||||
# Starts postgres + OxiCloud server, runs Hurl tests, tears everything down.
|
||||
#
|
||||
# Usage (from repo root):
|
||||
# bash tests/api/run.sh
|
||||
#
|
||||
# Prerequisites: docker, cargo, hurl ≥ 4.0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
COMMON="$REPO_ROOT/tests/common"
|
||||
API_DIR="$REPO_ROOT/tests/api"
|
||||
|
||||
# .env is the single source of truth for connection details and credentials.
|
||||
# shellcheck source=.env
|
||||
source "$API_DIR/.env"
|
||||
|
||||
# Derive server port from base_url (e.g. http://localhost:8087 → 8087)
|
||||
SERVER_PORT="${base_url##*:}"
|
||||
|
||||
# ── Helpers ───────────────────────────────────────────────────────────────────
|
||||
|
||||
log() { echo "[api-test] $*"; }
|
||||
die() { echo "[api-test] ERROR: $*" >&2; exit 1; }
|
||||
|
||||
wait_for_http() {
|
||||
local url="$1" timeout="${2:-60}"
|
||||
local deadline=$(( $(date +%s) + timeout ))
|
||||
until curl -sf "$url" >/dev/null 2>&1; do
|
||||
[[ $(date +%s) -ge $deadline ]] && die "Timeout waiting for $url"
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
# ── Teardown (always runs on exit) ────────────────────────────────────────────
|
||||
|
||||
SERVER_PID=""
|
||||
|
||||
cleanup() {
|
||||
if [[ -n "$SERVER_PID" ]]; then
|
||||
log "Stopping OxiCloud server (pid $SERVER_PID)..."
|
||||
kill "$SERVER_PID" 2>/dev/null || true
|
||||
wait "$SERVER_PID" 2>/dev/null || true
|
||||
fi
|
||||
bash "$COMMON/stop-db.sh"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
# ── 1. Start postgres ─────────────────────────────────────────────────────────
|
||||
|
||||
bash "$COMMON/spawn-db.sh"
|
||||
|
||||
# ── 2. Load shared server env + port from .env ───────────────────────────────
|
||||
|
||||
set -a
|
||||
# shellcheck source=../common/server.env
|
||||
source "$COMMON/server.env"
|
||||
OXICLOUD_SERVER_PORT=$SERVER_PORT
|
||||
OXICLOUD_STORAGE_PATH="$REPO_ROOT/tests/api/storage"
|
||||
set +a
|
||||
|
||||
mkdir -p "$OXICLOUD_STORAGE_PATH"
|
||||
|
||||
# ── 3. Start OxiCloud server ──────────────────────────────────────────────────
|
||||
|
||||
log "Building and starting OxiCloud server on port $SERVER_PORT..."
|
||||
cd "$REPO_ROOT"
|
||||
cargo run &
|
||||
SERVER_PID=$!
|
||||
log "Waiting for server at $base_url..."
|
||||
wait_for_http "$base_url/ready" 120
|
||||
log "Server is ready."
|
||||
|
||||
# ── 4. Run Hurl tests ─────────────────────────────────────────────────────────
|
||||
|
||||
log "Running Hurl tests..."
|
||||
hurl --variables-file "$API_DIR/.env" --test --jobs 1 \
|
||||
"$API_DIR/setup.hurl" \
|
||||
"$API_DIR/contacts.hurl"
|
||||
|
||||
log "All tests passed."
|
||||
@@ -0,0 +1,43 @@
|
||||
# =============================================================
|
||||
# OxiCloud – First-time admin setup
|
||||
# =============================================================
|
||||
# Creates the initial admin account. Only works once: the
|
||||
# endpoint is disabled after the first admin exists.
|
||||
#
|
||||
# Run:
|
||||
# hurl --variables-file tests/api/hurl.vars --test tests/api/setup.hurl
|
||||
# =============================================================
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 1 – Create the first admin account
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
POST {{base_url}}/api/setup
|
||||
Content-Type: application/json
|
||||
{
|
||||
"username": "{{username}}",
|
||||
"email": "{{email}}",
|
||||
"password": "{{password}}"
|
||||
}
|
||||
|
||||
HTTP 201
|
||||
[Asserts]
|
||||
jsonpath "$.username" == "{{username}}"
|
||||
jsonpath "$.email" == "{{email}}"
|
||||
jsonpath "$.role" == "admin"
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# Step 2 – Verify the endpoint is now disabled (admin exists)
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
POST {{base_url}}/api/setup
|
||||
Content-Type: application/json
|
||||
{
|
||||
"username": "another",
|
||||
"email": "another@example.com",
|
||||
"password": "irrelevant"
|
||||
}
|
||||
|
||||
HTTP 403
|
||||
[Asserts]
|
||||
jsonpath "$.error_type" == "SystemAlreadyInitialized"
|
||||
@@ -0,0 +1,18 @@
|
||||
# Shared test-server environment variables.
|
||||
# Sourced by tests/api/run.sh (shell) and read by tests/e2e/playwright.config.ts (Node).
|
||||
# Do NOT include OXICLOUD_SERVER_PORT or OXICLOUD_STORAGE_PATH here —
|
||||
# each test suite sets those to avoid port/directory conflicts.
|
||||
|
||||
DATABASE_URL=postgres://oxicloud_test:oxicloud_test@localhost:5433/oxicloud_test
|
||||
OXICLOUD_DB_CONNECTION_STRING=postgres://oxicloud_test:oxicloud_test@localhost:5433/oxicloud_test
|
||||
OXICLOUD_STATIC_PATH=./static
|
||||
OXICLOUD_JWT_SECRET=test-secret-do-not-use-in-prod-minimum-32-chars
|
||||
OXICLOUD_ENABLE_AUTH=true
|
||||
OXICLOUD_ENABLE_TRASH=true
|
||||
OXICLOUD_ENABLE_SEARCH=true
|
||||
OXICLOUD_ENABLE_FILE_SHARING=true
|
||||
OXICLOUD_ENABLE_MUSIC=true
|
||||
OXICLOUD_EXPOSE_SYSTEM_USERS=true
|
||||
OXICLOUD_WOPI_ENABLED=false
|
||||
OXICLOUD_OIDC_ENABLED=false
|
||||
RUST_LOG=info
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
COMPOSE_FILE="$(dirname "$0")/docker-compose.test.yml"
|
||||
|
||||
wait_for_port() {
|
||||
local host="$1" port="$2" timeout="${3:-30}"
|
||||
local deadline=$(( $(date +%s) + timeout ))
|
||||
until nc -z "$host" "$port" 2>/dev/null; do
|
||||
[[ $(date +%s) -ge $deadline ]] && echo "Timeout waiting for $host:$port" >&2 && exit 1
|
||||
sleep 0.5
|
||||
done
|
||||
}
|
||||
|
||||
echo "[setup] Starting test postgres..."
|
||||
docker compose -f "$COMPOSE_FILE" down -v 2>/dev/null || true
|
||||
docker compose -f "$COMPOSE_FILE" up -d
|
||||
echo "[setup] Waiting for postgres on port 5433..."
|
||||
wait_for_port 127.0.0.1 5433
|
||||
echo "[setup] Postgres is ready."
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
COMPOSE_FILE="$(dirname "$0")/docker-compose.test.yml"
|
||||
|
||||
echo "[teardown] Stopping test postgres..."
|
||||
docker compose -f "$COMPOSE_FILE" down -v
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
end to end tests via playwright
|
||||
@@ -4,9 +4,9 @@
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"pretest": "node -e \"(async()=>{await require('./spawn-db.js')()})().catch(e=>{console.error(e);process.exit(1)})\"",
|
||||
"pretest": "bash ../common/spawn-db.sh",
|
||||
"test": "npx playwright test",
|
||||
"posttest": "node -e \"(async()=>{await require('./stop-db.js')()})().catch(e=>{console.error(e);process.exit(1)})\""
|
||||
"posttest": "bash ../common/stop-db.sh"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
||||
@@ -1,4 +1,21 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
/** Parse a KEY=VALUE env file, skipping blank lines and comments. */
|
||||
function loadEnv(filePath: string): Record<string, string> {
|
||||
const env: Record<string, string> = {};
|
||||
for (const line of fs.readFileSync(filePath, 'utf-8').split('\n')) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith('#')) continue;
|
||||
const idx = trimmed.indexOf('=');
|
||||
if (idx === -1) continue;
|
||||
env[trimmed.slice(0, idx)] = trimmed.slice(idx + 1);
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
const commonEnv = loadEnv(path.join(__dirname, '../common/server.env'));
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './scenarios',
|
||||
@@ -39,19 +56,9 @@ export default defineConfig({
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe',
|
||||
env: {
|
||||
DATABASE_URL: 'postgres://oxicloud_test:oxicloud_test@localhost:5433/oxicloud_test',
|
||||
OXICLOUD_SERVER_PORT: 8087,
|
||||
OXICLOUD_DB_CONNECTION_STRING: 'postgres://oxicloud_test:oxicloud_test@localhost:5433/oxicloud_test',
|
||||
...commonEnv,
|
||||
OXICLOUD_SERVER_PORT: '8087',
|
||||
OXICLOUD_STORAGE_PATH: './tests/e2e/storage',
|
||||
OXICLOUD_STATIC_PATH: './static',
|
||||
OXICLOUD_JWT_SECRET: 'test-secret-do-not-use-in-prod-minimum-32-chars',
|
||||
OXICLOUD_ENABLE_AUTH: 'true',
|
||||
OXICLOUD_ENABLE_TRASH: 'true',
|
||||
OXICLOUD_ENABLE_SEARCH: 'true',
|
||||
OXICLOUD_ENABLE_FILE_SHARING: 'true',
|
||||
OXICLOUD_WOPI_ENABLED: 'false',
|
||||
OXICLOUD_OIDC_ENABLED: 'false',
|
||||
RUST_LOG: 'warn',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
const { execSync, spawnSync } = require('child_process');
|
||||
const net = require('net');
|
||||
const path = require('path');
|
||||
|
||||
const COMPOSE_FILE = path.join(__dirname, 'docker-compose.test.yml');
|
||||
const CMD = `docker compose -f ${COMPOSE_FILE}`;
|
||||
|
||||
function waitForPort(host, port, timeoutMs = 30_000) {
|
||||
const deadline = Date.now() + timeoutMs;
|
||||
return new Promise((resolve, reject) => {
|
||||
function attempt() {
|
||||
const sock = net.connect(port, host);
|
||||
sock.once('connect', () => { sock.destroy(); resolve(); });
|
||||
sock.once('error', () => {
|
||||
sock.destroy();
|
||||
if (Date.now() >= deadline) return reject(new Error(`Timeout waiting for ${host}:${port}`));
|
||||
setTimeout(attempt, 500);
|
||||
});
|
||||
}
|
||||
attempt();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = async function globalSetup() {
|
||||
console.log('[setup] Starting test postgres (database is empty) ...');
|
||||
execSync(`${CMD} down`, { stdio: 'inherit' });
|
||||
execSync(`${CMD} up -d`, { stdio: 'inherit' });
|
||||
console.log('[setup] Waiting for postgres on port 5433...');
|
||||
await waitForPort('127.0.0.1', 5433);
|
||||
console.log('[setup] Postgres is ready.');
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
const { execSync } = require('child_process');
|
||||
const path = require('path');
|
||||
|
||||
const COMPOSE_FILE = path.join(__dirname, 'docker-compose.test.yml');
|
||||
|
||||
module.exports = async function globalTeardown() {
|
||||
console.log('[teardown] Stopping test postgres...');
|
||||
execSync(`docker compose -f ${COMPOSE_FILE} down -v`, { stdio: 'inherit' });
|
||||
};
|
||||
Reference in New Issue
Block a user