feat: OpsxDB 桌面数据库客户端首版入库

含工作台/连库多引擎字段与 SSH·SSL、结果编辑、Redis 键浏览、
Tauri 桌面与 docs/落地页;排除本地构建产物与 sidecar 二进制。
This commit is contained in:
logan committed 2026-09-19 22:43:45 +08:00
commit f8740d27f7
240 files changed
+21625

No files matched your search

+173
View File
@@ -0,0 +1,173 @@
#!/usr/bin/env bash
# OpsxDB multi-driver CRUD smoke test via local API :8788
set -uo pipefail
API="${OPSXDB_API:-http://127.0.0.1:8788}"
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$(dirname "$0")"
n_ok=0; n_fail=0
ok() { echo " OK $*"; n_ok=$((n_ok+1)); }
bad() { echo " FAIL $*"; n_fail=$((n_fail+1)); }
post() {
curl -sS -m 30 -H 'Content-Type: application/json' -d "$1" "$API$2"
}
wait_health() {
local name="$1" tries="${2:-60}"
for i in $(seq 1 "$tries"); do
local st
st=$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$name" 2>/dev/null || echo missing)
[[ "$st" == "healthy" || "$st" == "running" ]] && return 0
sleep 2
done
return 1
}
crud_sql() {
local driver="$1" host="$2" port="$3" user="$4" password="$5" db="$6" dialect="$7"
local base
base=$(printf '{"driver":"%s","host":"%s","port":%s,"user":"%s","password":"%s","database":"%s"}' \
"$driver" "$host" "$port" "$user" "$password" "$db")
echo "== $driver =="
local tc
tc=$(post "$base" /api/db/test-connection)
echo "$tc" | grep -q '"ok":true' && ok "test-connection" || { bad "test-connection $tc"; return; }
local dbs
dbs=$(post "$base" /api/db/databases)
echo "$dbs" | grep -q 'databases' && ok "databases" || bad "databases $dbs"
local tables
tables=$(post "$base" /api/db/tables)
echo "$tables" | grep -qi 'users\|key\|tables' && ok "tables" || ok "tables (raw) $tables"
local sel ins upd del
case "$dialect" in
mysql)
sel='SELECT id,name FROM users ORDER BY id LIMIT 5'
ins="INSERT INTO users (name, email, status) VALUES ('grace','grace@demo.local',1)"
upd="UPDATE users SET status=0 WHERE name='grace'"
del="DELETE FROM users WHERE name='grace'"
;;
postgres)
sel='SELECT id,name FROM users ORDER BY id LIMIT 5'
ins="INSERT INTO users (name, email, status) VALUES ('grace','grace@demo.local',1)"
upd="UPDATE users SET status=0 WHERE name='grace'"
del="DELETE FROM users WHERE name='grace'"
;;
mssql)
sel='SELECT TOP 5 id,name FROM dbo.users ORDER BY id'
ins="INSERT INTO dbo.users (name, email, status) VALUES (N'grace',N'grace@demo.local',1)"
upd="UPDATE dbo.users SET status=0 WHERE name=N'grace'"
del="DELETE FROM dbo.users WHERE name=N'grace'"
;;
oracle)
sel='SELECT id,name FROM users ORDER BY id FETCH FIRST 5 ROWS ONLY'
ins="INSERT INTO users (name, email, status) VALUES ('grace','grace@demo.local',1)"
upd="UPDATE users SET status=0 WHERE name='grace'"
del="DELETE FROM users WHERE name='grace'"
;;
sqlite)
sel='SELECT id,name FROM users ORDER BY id LIMIT 5'
ins="INSERT INTO users (name, email, status) VALUES ('grace','grace@demo.local',1)"
upd="UPDATE users SET status=0 WHERE name='grace'"
del="DELETE FROM users WHERE name='grace'"
;;
redis)
sel='KEYS *'
ins='SET opsxdb:demo:grace hello'
upd='GET opsxdb:demo:grace'
del='DEL opsxdb:demo:grace'
;;
esac
local body
body=$(printf '%s' "$base" | python3 -c 'import json,sys; d=json.load(sys.stdin); d["sql"]=sys.argv[1]; print(json.dumps(d))' "$sel")
local r
r=$(post "$body" /api/db/exec)
echo "$r" | grep -vq '"error":"[^"]' && ok "SELECT/KEYS" || bad "SELECT $r"
body=$(printf '%s' "$base" | python3 -c 'import json,sys; d=json.load(sys.stdin); d["sql"]=sys.argv[1]; print(json.dumps(d))' "$ins")
r=$(post "$body" /api/db/exec)
echo "$r" | grep -vq '"error":"[^"]' && ok "INSERT/SET" || bad "INSERT $r"
body=$(printf '%s' "$base" | python3 -c 'import json,sys; d=json.load(sys.stdin); d["sql"]=sys.argv[1]; print(json.dumps(d))' "$upd")
r=$(post "$body" /api/db/exec)
echo "$r" | grep -vq '"error":"[^"]' && ok "UPDATE/GET" || bad "UPDATE $r"
body=$(printf '%s' "$base" | python3 -c 'import json,sys; d=json.load(sys.stdin); d["sql"]=sys.argv[1]; print(json.dumps(d))' "$del")
r=$(post "$body" /api/db/exec)
echo "$r" | grep -vq '"error":"[^"]' && ok "DELETE/DEL" || bad "DELETE $r"
}
echo "API=$API"
curl -sS -m 5 "$API/api/health" || { echo "API down"; exit 1; }
echo
# --- SQLite (no docker) ---
SQLITE_DB="$ROOT/tests/tmp/demo.sqlite"
mkdir -p "$ROOT/tests/tmp"
rm -f "$SQLITE_DB"
sqlite3 "$SQLITE_DB" < init/sqlite/01_demo.sql
crud_sql sqlite "" 0 "" "" "$SQLITE_DB" sqlite
# --- MariaDB ---
./dbctl.sh up b
wait_health opsxdb-mariadb 40 || true
docker exec -i opsxdb-mariadb mariadb -uroot -p'Demo@123' < init/mariadb/01_demo.sql 2>/dev/null \
|| docker exec -i opsxdb-mariadb mysql -uroot -p'Demo@123' < init/mariadb/01_demo.sql
crud_sql mariadb 127.0.0.1 3307 root 'Demo@123' demo mysql
# --- PostgreSQL ---
./dbctl.sh up c
wait_health opsxdb-postgres 40
docker exec -i opsxdb-postgres psql -U opsx -d demo < init/postgres/01_demo.sql >/dev/null
crud_sql postgresql 127.0.0.1 5432 opsx 'Demo@123' demo postgres
# --- Redis ---
./dbctl.sh up f
wait_health opsxdb-redis 30
crud_sql redis 127.0.0.1 6379 "" "" 0 redis
# --- SQL Server ---
./dbctl.sh up d
wait_health opsxdb-mssql 120 || true
for i in $(seq 1 60); do
if docker exec opsxdb-mssql /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'Demo@12345' -C -Q 'SELECT 1' >/dev/null 2>&1 \
|| docker exec opsxdb-mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'Demo@12345' -Q 'SELECT 1' >/dev/null 2>&1; then
echo "mssql sqlcmd ready"
break
fi
sleep 3
done
docker cp init/mssql/01_demo.sql opsxdb-mssql:/tmp/01_demo.sql
docker exec opsxdb-mssql /opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'Demo@12345' -C -i /tmp/01_demo.sql \
|| docker exec opsxdb-mssql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'Demo@12345' -i /tmp/01_demo.sql \
|| true
# login to master then demo CRUD
base_master='{"driver":"sqlserver","host":"127.0.0.1","port":1433,"user":"sa","password":"Demo@12345","database":"master"}'
echo "== sqlserver master ping =="
r=$(post "$base_master" /api/db/test-connection)
echo "$r" | grep -q '"ok":true' && ok "test-connection master" || bad "test-connection master $r"
crud_sql sqlserver 127.0.0.1 1433 sa 'Demo@12345' demo mssql
# --- Oracle (slow) ---
./dbctl.sh up e
wait_health opsxdb-oracle 180 || wait_health opsxdb-oracle 120 || true
docker cp init/oracle/01_demo.sql opsxdb-oracle:/tmp/01_demo.sql
docker exec opsxdb-oracle bash -lc "echo exit | sqlplus -s opsx/Demo@123@//localhost/XEPDB1 @/tmp/01_demo.sql" \
|| docker exec opsxdb-oracle bash -lc "echo exit | sqlplus -s system/Demo@123@//localhost/XEPDB1 @/tmp/01_demo.sql" \
|| true
crud_sql oracle 127.0.0.1 1521 opsx 'Demo@123' XEPDB1 oracle
# --- MySQL last (restore default) ---
./dbctl.sh up a
wait_health opsxdb-mysql 40
docker exec -i opsxdb-mysql mysql -uroot -p'Demo@123' < init/mysql/01_demo.sql
crud_sql mysql 127.0.0.1 3306 root 'Demo@123' demo mysql
echo
echo "==== SUMMARY ok=$n_ok fail=$n_fail ===="
[[ "$n_fail" -eq 0 ]]