feat: OpsxDB 桌面数据库客户端首版入库
含工作台/连库多引擎字段与 SSH·SSL、结果编辑、Redis 键浏览、 Tauri 桌面与 docs/落地页;排除本地构建产物与 sidecar 二进制。
No files matched your search
@@ -0,0 +1,164 @@
|
||||
# OpsxDB 测试数据库环境
|
||||
|
||||
联调 / 回归用的 Docker 库。**不要同时开多个**,否则占内存、干扰性能测试。
|
||||
|
||||
## a–e 对照
|
||||
|
||||
| 代号 | 服务 | 宿主机端口 | 账号 | 密码 | 默认库 |
|
||||
|------|------|------------|------|------|--------|
|
||||
| **a** | MySQL 8 | `3306` | `root` / `opsx` | `Demo@123` | `demo` |
|
||||
| **b** | MariaDB 11 | `3307` | `root` / `opsx` | `Demo@123` | `demo` |
|
||||
| **c** | PostgreSQL 16 | `5432` | `opsx` | `Demo@123` | `demo` |
|
||||
| **d** | SQL Server 2022 | `1433` | `sa` | `Demo@12345` | 先建 `demo` |
|
||||
| **e** | Oracle XE 21 | `1521` | `opsx`(或 system) | `Demo@123` | Service `XEPDB1` |
|
||||
| **f** | Redis 7 | `6379` | — | — | db `0` |
|
||||
| **g** | ZooKeeper 3.9 | `2181` | — | — | 无认证 |
|
||||
| **h** | Elasticsearch 8.15 | `9200` | — | — | 安全已关,本机联调 |
|
||||
| **i** | InfluxDB 2.7 | `8086` | `opsx` | `Demo@123` | org `opsx` / bucket `demo` / token `opsxdb-demo-token` |
|
||||
|
||||
SQL Server 首次进库:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE demo;
|
||||
```
|
||||
|
||||
## 常用命令
|
||||
|
||||
```bash
|
||||
cd /Users/logan/devops/opsxdb/tests
|
||||
|
||||
./dbctl.sh pull # 国内加速拉取 ZK / ES / InfluxDB
|
||||
./dbctl.sh up a # 或 up mysql —— 只起这一个
|
||||
./dbctl.sh up g # ZooKeeper :2181
|
||||
./dbctl.sh up h # Elasticsearch :9200(吃内存)
|
||||
./dbctl.sh up i # InfluxDB :8086
|
||||
./dbctl.sh up c # 只开 PostgreSQL(会先停掉其它测试库)
|
||||
./dbctl.sh status
|
||||
./dbctl.sh logs mysql
|
||||
./dbctl.sh down mysql # 停一个(保留数据卷)
|
||||
./dbctl.sh down # 停全部
|
||||
./dbctl.sh reset oracle # 删卷重来(镜像大,慎用)
|
||||
```
|
||||
|
||||
## 在 OpsxDB 里怎么连
|
||||
|
||||
1. 仓库根目录 `./run.sh web` → http://127.0.0.1:5174
|
||||
2. 新建连接 → 选驱动 → 填上表参数 → 测试连接
|
||||
3. 打开 `demo`,执行 `SELECT * FROM users;`(MySQL / MariaDB / PG 已有种子表)
|
||||
|
||||
## 注意
|
||||
|
||||
- 一次只 `up` 一个;`dbctl.sh up` 发现其它测试库在跑会先停掉。
|
||||
- Oracle / SQL Server / Elasticsearch 镜像大、启动慢,只在验证对应项时再开。
|
||||
- `down` 不删卷,`reset` 才删。
|
||||
- 镜像默认走 DaoCloud:`DOCKER_MIRROR=docker.m.daocloud.io`(失败再试 `docker.1ms.run`)。
|
||||
|
||||
ZooKeeper / ES / Influx 在 OpsxDB 里:
|
||||
|
||||
| 类型 | 主机 | 端口 | 说明 |
|
||||
|------|------|------|------|
|
||||
| ZooKeeper | 127.0.0.1 | 2181 | 用户密码留空 |
|
||||
| Elasticsearch | 127.0.0.1 | 9200 | 用户密码留空(xpack 已关) |
|
||||
| InfluxDB | 127.0.0.1 | 8086 | 用户 `opsx` / 密码 `Demo@123`,库名填 `demo` |
|
||||
|
||||
|
||||
|
||||
### demo
|
||||
```
|
||||
## ---------- 先拉镜像 ---------- ##
|
||||
docker pull mysql:8
|
||||
docker pull mariadb:11
|
||||
docker pull postgres:16
|
||||
# 国内加速拉完打短 tag,不要把 daocloud/mcr 前缀留在本地名里
|
||||
# mcr.m.daocloud.io/mssql/server:2022-latest → mssql/server:2022-latest
|
||||
# docker.m.daocloud.io/library/zookeeper:3.9 → zookeeper:3.9
|
||||
./dbctl.sh pull mssql
|
||||
./dbctl.sh pull new
|
||||
docker pull gvenzl/oracle-xe:21-slim
|
||||
docker pull redis:7-alpine
|
||||
docker pull ubuntu:24.04
|
||||
docker pull eclipse-temurin:17-jdk
|
||||
docker pull eclipse-temurin:17-jre
|
||||
docker pull golang:1.25-alpine
|
||||
docker pull nginx:alpine
|
||||
docker pull maven:3.9-eclipse-temurin-17
|
||||
|
||||
|
||||
## ---------- 后台常驻(数据库 / 缓存) ---------- ##
|
||||
# MySQL 8
|
||||
docker run -d --name demo-mysql --restart unless-stopped \
|
||||
-p 3306:3306 \
|
||||
-e MYSQL_ROOT_PASSWORD=Demo@123 \
|
||||
-e MYSQL_DATABASE=demo \
|
||||
mysql:8
|
||||
|
||||
# MariaDB 11(宿主机 3307,避免和 MySQL 抢端口)
|
||||
docker run -d --name demo-maria --restart unless-stopped \
|
||||
-p 3307:3306 \
|
||||
-e MARIADB_ROOT_PASSWORD=Demo@123 \
|
||||
-e MARIADB_DATABASE=demo \
|
||||
mariadb:11
|
||||
|
||||
# PostgreSQL 16
|
||||
docker run -d --name demo-pg --restart unless-stopped \
|
||||
-p 5432:5432 \
|
||||
-e POSTGRES_PASSWORD=Demo@123 \
|
||||
-e POSTGRES_DB=demo \
|
||||
postgres:16
|
||||
|
||||
# SQL Server 2022
|
||||
docker run -d --name demo-mssql --restart unless-stopped \
|
||||
-p 1433:1433 \
|
||||
-e ACCEPT_EULA=Y \
|
||||
-e MSSQL_SA_PASSWORD='Demo@12345' \
|
||||
mssql/server:2022-latest
|
||||
|
||||
# Oracle XE 21(镜像大,第一次慢)
|
||||
docker run -d --name demo-oracle --restart unless-stopped \
|
||||
-p 1521:1521 \
|
||||
-e ORACLE_PASSWORD=Demo@123 \
|
||||
gvenzl/oracle-xe:21-slim
|
||||
|
||||
# Redis 7
|
||||
docker run -d --name demo-redis --restart unless-stopped \
|
||||
-p 6379:6379 \
|
||||
redis:7-alpine
|
||||
|
||||
# ZooKeeper / ES / Influx 请用 ./dbctl.sh pull && ./dbctl.sh up g|h|i(国内加速)
|
||||
|
||||
|
||||
## ---------- 测试 ---------- ##
|
||||
# Ubuntu 24.04 LTS
|
||||
docker run -it --rm ubuntu:24.04 bash
|
||||
|
||||
# JDK 17
|
||||
docker run -it --rm -v "$PWD":/app -w /app eclipse-temurin:17-jdk java -version
|
||||
|
||||
# Maven + JDK 17
|
||||
docker run -it --rm -v "$PWD":/app -w /app maven:3.9-eclipse-temurin-17 mvn -v
|
||||
|
||||
# Go 1.25
|
||||
docker run --rm golang:1.25-alpine go version
|
||||
docker run --rm -v "$PWD":/src -w /src golang:1.25-alpine go build -v .
|
||||
|
||||
# Nginx 试一下
|
||||
docker run -d --name demo-nginx -p 8080:80 nginx:alpine
|
||||
```
|
||||
|
||||
|
||||
## 驱动验收(本机)
|
||||
|
||||
| 驱动 | 连接 | 库表 | CRUD | 备注 |
|
||||
|------|------|------|------|------|
|
||||
| MySQL | OK | OK | OK | `./dbctl.sh up a` |
|
||||
| MariaDB | OK | OK | OK | `./dbctl.sh up b` 端口 3307 |
|
||||
| PostgreSQL | OK | OK | OK | `./dbctl.sh up c` 用户 opsx |
|
||||
| SQL Server | OK | OK | OK | `./dbctl.sh up d` sa / Demo@12345(Apple Silicon 模拟较慢) |
|
||||
| SQLite | OK | OK | OK | database 填文件路径 |
|
||||
| Redis | OK | OK | OK | `./dbctl.sh up f`;编辑器执行 `PING`/`GET`/`SET`/`DEL`/`KEYS` |
|
||||
| ZooKeeper | 镜像已备 | — | — | `./dbctl.sh up g`;驱动未就绪,`:2181` 无认证 |
|
||||
| Elasticsearch | 镜像已备 | — | — | `./dbctl.sh up h`;驱动未就绪,`:9200` 已关 xpack |
|
||||
| InfluxDB | 镜像已备 | — | — | `./dbctl.sh up i`;驱动未就绪,opsx / Demo@123 / bucket demo |
|
||||
| Oracle | 代码就绪 | — | 本机未跑通 | Apple Silicon 上 `gvenzl/oracle-xe` 报 ORA-00442,需 x86 环境或真库 |
|
||||
|
||||
冒烟脚本:`./tests/verify-crud.sh`(一次只起一个库)。
|
||||
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env bash
|
||||
# 按需启停测试库,禁止一次全开。
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
ALIASES_HELP='mysql|a mariadb|b postgres|c mssql|d oracle|e redis|f zookeeper|g elasticsearch|h influxdb|i'
|
||||
ALL_PROFILES=(mysql mariadb postgres mssql oracle redis zookeeper elasticsearch influxdb)
|
||||
|
||||
# 国内加速(DaoCloud 镜像站)。可用 DOCKER_MIRROR 覆盖,例如 docker.1ms.run
|
||||
DOCKER_MIRROR="${DOCKER_MIRROR:-docker.m.daocloud.io}"
|
||||
DOCKER_MIRROR_FALLBACK="${DOCKER_MIRROR_FALLBACK:-docker.1ms.run}"
|
||||
|
||||
resolve() {
|
||||
case "$1" in
|
||||
a|mysql) echo mysql ;;
|
||||
b|mariadb|maria) echo mariadb ;;
|
||||
c|postgres|pg|postgresql) echo postgres ;;
|
||||
d|mssql|sqlserver|sqlsrv) echo mssql ;;
|
||||
e|oracle) echo oracle ;;
|
||||
f|redis) echo redis ;;
|
||||
g|zk|zookeeper) echo zookeeper ;;
|
||||
h|es|elastic|elasticsearch) echo elasticsearch ;;
|
||||
i|influx|influxdb) echo influxdb ;;
|
||||
*) echo ""; return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
compose_all_profiles() {
|
||||
local args=()
|
||||
local p
|
||||
for p in "${ALL_PROFILES[@]}"; do
|
||||
args+=(--profile "$p")
|
||||
done
|
||||
echo "${args[@]}"
|
||||
}
|
||||
|
||||
# 国内源路径 → 本地短名。拉完摘掉带源前缀的 tag,层仍在。
|
||||
# zookeeper:3.9 ← docker.m.daocloud.io/library/zookeeper:3.9
|
||||
# mssql/server:2022-latest ← mcr.m.daocloud.io/mssql/server:2022-latest
|
||||
mirror_src() {
|
||||
case "$1" in
|
||||
mssql/server:*|mssql/*) echo "mcr.m.daocloud.io/$1" ;;
|
||||
*) echo "${DOCKER_MIRROR}/library/$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
mirror_src_fallback() {
|
||||
case "$1" in
|
||||
mssql/server:*|mssql/*) echo "mcr.microsoft.com/$1" ;;
|
||||
*) echo "${DOCKER_MIRROR_FALLBACK}/library/$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
pull_mirrored() {
|
||||
local official="$1"
|
||||
if docker image inspect "$official" >/dev/null 2>&1; then
|
||||
echo "[OK] 已有本地镜像 $official"
|
||||
return 0
|
||||
fi
|
||||
local src
|
||||
for src in "$(mirror_src "$official")" "$(mirror_src_fallback "$official")"; do
|
||||
echo "[INFO] 从 $src 拉取 …"
|
||||
if docker pull "$src"; then
|
||||
docker tag "$src" "$official"
|
||||
if [[ "$src" != "$official" ]]; then
|
||||
docker rmi "$src" >/dev/null 2>&1 || true
|
||||
fi
|
||||
echo "[OK] $official"
|
||||
return 0
|
||||
fi
|
||||
echo "[WARN] $src 失败,尝试下一个"
|
||||
done
|
||||
echo "[ERR] 无法拉取 $official"
|
||||
return 1
|
||||
}
|
||||
|
||||
running_profiles() {
|
||||
docker compose ps --services --status running 2>/dev/null || true
|
||||
}
|
||||
|
||||
cmd_up() {
|
||||
local svc
|
||||
svc=$(resolve "${1:-}") || { echo "用法: $0 up <${ALIASES_HELP}>"; exit 1; }
|
||||
local cur
|
||||
cur=$(running_profiles)
|
||||
if [[ -n "$cur" ]]; then
|
||||
local other
|
||||
other=$(echo "$cur" | grep -v "^${svc}$" || true)
|
||||
if [[ -n "$other" ]]; then
|
||||
echo "[WARN] 已有其它测试库在跑,先停以免抢资源: $other"
|
||||
# shellcheck disable=SC2086
|
||||
docker compose $(compose_all_profiles) stop $other || true
|
||||
fi
|
||||
fi
|
||||
echo "[INFO] 启动 $svc …"
|
||||
docker compose --profile "$svc" up -d "$svc"
|
||||
echo "[OK] $svc 已请求启动。连接参数见 README.md"
|
||||
docker compose --profile "$svc" ps
|
||||
}
|
||||
|
||||
cmd_down() {
|
||||
if [[ -z "${1:-}" ]]; then
|
||||
echo "[INFO] 停止全部 opsxdb-tests 服务"
|
||||
# shellcheck disable=SC2046
|
||||
docker compose $(compose_all_profiles) down
|
||||
return
|
||||
fi
|
||||
local svc
|
||||
svc=$(resolve "$1") || { echo "未知库: $1"; exit 1; }
|
||||
docker compose --profile "$svc" stop "$svc"
|
||||
echo "[OK] 已停止 $svc(数据卷保留;要清数据用: $0 reset $svc)"
|
||||
}
|
||||
|
||||
cmd_reset() {
|
||||
local svc
|
||||
svc=$(resolve "${1:-}") || { echo "用法: $0 reset <服务>"; exit 1; }
|
||||
docker compose --profile "$svc" stop "$svc" || true
|
||||
docker compose --profile "$svc" rm -f "$svc" || true
|
||||
case "$svc" in
|
||||
mysql) docker volume rm -f opsxdb-tests_opsxdb_mysql_data 2>/dev/null || true ;;
|
||||
mariadb) docker volume rm -f opsxdb-tests_opsxdb_mariadb_data 2>/dev/null || true ;;
|
||||
postgres) docker volume rm -f opsxdb-tests_opsxdb_pg_data 2>/dev/null || true ;;
|
||||
mssql) docker volume rm -f opsxdb-tests_opsxdb_mssql_data 2>/dev/null || true ;;
|
||||
oracle) docker volume rm -f opsxdb-tests_opsxdb_oracle_data 2>/dev/null || true ;;
|
||||
redis) ;;
|
||||
zookeeper)
|
||||
docker volume rm -f opsxdb-tests_opsxdb_zk_data opsxdb-tests_opsxdb_zk_datalog 2>/dev/null || true
|
||||
;;
|
||||
elasticsearch) docker volume rm -f opsxdb-tests_opsxdb_es_data 2>/dev/null || true ;;
|
||||
influxdb) docker volume rm -f opsxdb-tests_opsxdb_influx_data 2>/dev/null || true ;;
|
||||
esac
|
||||
echo "[OK] $svc 已重置(下次 up 会重新初始化)"
|
||||
}
|
||||
|
||||
cmd_status() {
|
||||
echo "=== 运行中的测试库 ==="
|
||||
docker compose ps 2>/dev/null || docker ps --filter name=opsxdb- --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
|
||||
}
|
||||
|
||||
cmd_logs() {
|
||||
local svc
|
||||
svc=$(resolve "${1:-}") || { echo "用法: $0 logs <服务>"; exit 1; }
|
||||
docker compose --profile "$svc" logs -f --tail=100 "$svc"
|
||||
}
|
||||
|
||||
cmd_pull() {
|
||||
local target="${1:-new}"
|
||||
case "$target" in
|
||||
new|ghi|extra)
|
||||
echo "[INFO] 拉取 ZooKeeper / Elasticsearch / InfluxDB(国内加速,本地短 tag)"
|
||||
pull_mirrored zookeeper:3.9
|
||||
pull_mirrored elasticsearch:8.15.3
|
||||
pull_mirrored influxdb:2.7
|
||||
;;
|
||||
d|mssql|sqlserver) pull_mirrored mssql/server:2022-latest ;;
|
||||
g|zk|zookeeper) pull_mirrored zookeeper:3.9 ;;
|
||||
h|es|elastic|elasticsearch) pull_mirrored elasticsearch:8.15.3 ;;
|
||||
i|influx|influxdb) pull_mirrored influxdb:2.7 ;;
|
||||
*)
|
||||
local svc
|
||||
svc=$(resolve "$target") || { echo "用法: $0 pull [new|zookeeper|elasticsearch|influxdb]"; exit 1; }
|
||||
case "$svc" in
|
||||
mssql) pull_mirrored mssql/server:2022-latest ;;
|
||||
zookeeper) pull_mirrored zookeeper:3.9 ;;
|
||||
elasticsearch) pull_mirrored elasticsearch:8.15.3 ;;
|
||||
influxdb) pull_mirrored influxdb:2.7 ;;
|
||||
*) echo "请直接 docker compose pull,或: $0 pull new"; exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
echo
|
||||
docker images --format 'table {{.Repository}}\t{{.Tag}}\t{{.Size}}' | grep -E 'REPOSITORY|zookeeper|elasticsearch|influxdb' || true
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<USAGE
|
||||
OpsxDB 测试库控制(一次只建议开一个)
|
||||
|
||||
./dbctl.sh up <服务>
|
||||
./dbctl.sh down [服务] # 省略则停全部
|
||||
./dbctl.sh reset <服务> # 删容器+数据卷
|
||||
./dbctl.sh pull [new] # 国内加速拉取 ZK / ES / InfluxDB
|
||||
./dbctl.sh status
|
||||
./dbctl.sh logs <服务>
|
||||
|
||||
a–i: a=MySQL b=MariaDB c=PostgreSQL d=SQL Server e=Oracle
|
||||
f=Redis g=ZooKeeper h=Elasticsearch i=InfluxDB
|
||||
USAGE
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
up) shift; cmd_up "$@" ;;
|
||||
down|stop) shift; cmd_down "$@" ;;
|
||||
reset) shift; cmd_reset "$@" ;;
|
||||
pull) shift; cmd_pull "$@" ;;
|
||||
status|ps) cmd_status ;;
|
||||
logs) shift; cmd_logs "$@" ;;
|
||||
help|-h|--help|"") usage ;;
|
||||
*) echo "未知命令: $1"; usage; exit 1 ;;
|
||||
esac
|
||||
@@ -0,0 +1,189 @@
|
||||
# OpsxDB 测试库 —— 务必按需启动,不要一次全开(吃内存/影响压测)
|
||||
# 用法见 README.md / ./dbctl.sh
|
||||
|
||||
name: opsxdb-tests
|
||||
|
||||
services:
|
||||
# a) MySQL 8
|
||||
mysql:
|
||||
profiles: ["mysql", "a"]
|
||||
image: mysql:8.4
|
||||
container_name: opsxdb-mysql
|
||||
ports: ["3306:3306"]
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: Demo@123
|
||||
MYSQL_DATABASE: demo
|
||||
MYSQL_USER: opsx
|
||||
MYSQL_PASSWORD: Demo@123
|
||||
volumes:
|
||||
- ./init/mysql:/docker-entrypoint-initdb.d:ro
|
||||
- opsxdb_mysql_data:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-pDemo@123"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
|
||||
# b) MariaDB 11(宿主机 3307,避免与 MySQL 抢 3306)
|
||||
mariadb:
|
||||
profiles: ["mariadb", "b"]
|
||||
image: mariadb:11
|
||||
container_name: opsxdb-mariadb
|
||||
ports: ["3307:3306"]
|
||||
environment:
|
||||
MARIADB_ROOT_PASSWORD: Demo@123
|
||||
MARIADB_DATABASE: demo
|
||||
MARIADB_USER: opsx
|
||||
MARIADB_PASSWORD: Demo@123
|
||||
volumes:
|
||||
- ./init/mysql:/docker-entrypoint-initdb.d:ro
|
||||
- opsxdb_mariadb_data:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
|
||||
# c) PostgreSQL 16
|
||||
postgres:
|
||||
profiles: ["postgres", "c"]
|
||||
image: postgres:16
|
||||
container_name: opsxdb-postgres
|
||||
ports: ["5432:5432"]
|
||||
environment:
|
||||
POSTGRES_PASSWORD: Demo@123
|
||||
POSTGRES_USER: opsx
|
||||
POSTGRES_DB: demo
|
||||
volumes:
|
||||
- ./init/postgres:/docker-entrypoint-initdb.d:ro
|
||||
- opsxdb_pg_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U opsx -d demo"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
|
||||
# d) SQL Server 2022(密码需满足复杂度)
|
||||
mssql:
|
||||
profiles: ["mssql", "sqlserver", "d"]
|
||||
image: mssql/server:2022-latest
|
||||
container_name: opsxdb-mssql
|
||||
ports: ["1433:1433"]
|
||||
environment:
|
||||
ACCEPT_EULA: "Y"
|
||||
MSSQL_SA_PASSWORD: "Demo@12345"
|
||||
volumes:
|
||||
- opsxdb_mssql_data:/var/opt/mssql
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'Demo@12345' -C -Q 'SELECT 1' || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 30
|
||||
start_period: 30s
|
||||
|
||||
# e) Oracle XE(镜像大,首次拉取慢;默认别开)
|
||||
oracle:
|
||||
profiles: ["oracle", "e"]
|
||||
image: gvenzl/oracle-xe:21-slim
|
||||
container_name: opsxdb-oracle
|
||||
ports: ["1521:1521"]
|
||||
environment:
|
||||
ORACLE_PASSWORD: Demo@123
|
||||
APP_USER: opsx
|
||||
APP_USER_PASSWORD: Demo@123
|
||||
volumes:
|
||||
- opsxdb_oracle_data:/opt/oracle/oradata
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh"]
|
||||
interval: 15s
|
||||
timeout: 10s
|
||||
retries: 40
|
||||
start_period: 60s
|
||||
|
||||
# f) Redis 7
|
||||
redis:
|
||||
profiles: ["redis", "f"]
|
||||
image: redis:7-alpine
|
||||
container_name: opsxdb-redis
|
||||
ports: ["6379:6379"]
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
|
||||
# g) ZooKeeper 3.9(无账号;四字命令放开便于探活)
|
||||
zookeeper:
|
||||
profiles: ["zookeeper", "zk", "g"]
|
||||
image: zookeeper:3.9
|
||||
container_name: opsxdb-zookeeper
|
||||
ports: ["2181:2181"]
|
||||
environment:
|
||||
ZOO_MY_ID: "1"
|
||||
ZOO_4LW_COMMANDS_WHITELIST: srvr,ruok,stat,mntr,conf
|
||||
ZOO_TICK_TIME: "2000"
|
||||
volumes:
|
||||
- opsxdb_zk_data:/data
|
||||
- opsxdb_zk_datalog:/datalog
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "zkServer.sh status || exit 1"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
|
||||
# h) Elasticsearch 8(关安全,本机联调用;吃内存,一次只开这一个)
|
||||
elasticsearch:
|
||||
profiles: ["elasticsearch", "es", "h"]
|
||||
image: elasticsearch:8.15.3
|
||||
container_name: opsxdb-elasticsearch
|
||||
ports: ["9200:9200", "9300:9300"]
|
||||
environment:
|
||||
discovery.type: single-node
|
||||
xpack.security.enabled: "false"
|
||||
xpack.security.http.ssl.enabled: "false"
|
||||
xpack.security.transport.ssl.enabled: "false"
|
||||
cluster.name: opsxdb
|
||||
ingest.geoip.downloader.enabled: "false"
|
||||
ES_JAVA_OPTS: "-Xms512m -Xmx512m"
|
||||
volumes:
|
||||
- opsxdb_es_data:/usr/share/elasticsearch/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:9200 >/dev/null || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 8s
|
||||
retries: 30
|
||||
start_period: 30s
|
||||
|
||||
# i) InfluxDB 2.7
|
||||
influxdb:
|
||||
profiles: ["influxdb", "influx", "i"]
|
||||
image: influxdb:2.7
|
||||
container_name: opsxdb-influxdb
|
||||
ports: ["8086:8086"]
|
||||
environment:
|
||||
DOCKER_INFLUXDB_INIT_MODE: setup
|
||||
DOCKER_INFLUXDB_INIT_USERNAME: opsx
|
||||
DOCKER_INFLUXDB_INIT_PASSWORD: Demo@123
|
||||
DOCKER_INFLUXDB_INIT_ORG: opsx
|
||||
DOCKER_INFLUXDB_INIT_BUCKET: demo
|
||||
DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: opsxdb-demo-token
|
||||
volumes:
|
||||
- opsxdb_influx_data:/var/lib/influxdb2
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "influx ping || curl -fsS http://127.0.0.1:8086/health >/dev/null || exit 1"]
|
||||
interval: 8s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
start_period: 15s
|
||||
|
||||
|
||||
volumes:
|
||||
opsxdb_mysql_data:
|
||||
opsxdb_mariadb_data:
|
||||
opsxdb_pg_data:
|
||||
opsxdb_mssql_data:
|
||||
opsxdb_oracle_data:
|
||||
opsxdb_zk_data:
|
||||
opsxdb_zk_datalog:
|
||||
opsxdb_es_data:
|
||||
opsxdb_influx_data:
|
||||
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 90 KiB |
@@ -0,0 +1,53 @@
|
||||
CREATE DATABASE IF NOT EXISTS demo DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
USE demo;
|
||||
|
||||
DROP TABLE IF EXISTS order_items;
|
||||
DROP TABLE IF EXISTS orders;
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
||||
CREATE TABLE users (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
name VARCHAR(64) NOT NULL,
|
||||
email VARCHAR(128) NULL,
|
||||
status TINYINT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE orders (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id INT NOT NULL,
|
||||
amount DECIMAL(12,2) NOT NULL DEFAULT 0,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_orders_user (user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE order_items (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
order_id INT NOT NULL,
|
||||
sku VARCHAR(64) NOT NULL,
|
||||
qty INT NOT NULL DEFAULT 1,
|
||||
price DECIMAL(12,2) NOT NULL DEFAULT 0,
|
||||
INDEX idx_items_order (order_id)
|
||||
);
|
||||
|
||||
INSERT INTO users (name, email, status) VALUES
|
||||
('alice', 'alice@demo.local', 1),
|
||||
('bob', 'bob@demo.local', 1),
|
||||
('carol', 'carol@demo.local', 1),
|
||||
('dave', 'dave@demo.local', 0),
|
||||
('erin', 'erin@demo.local', 1);
|
||||
|
||||
INSERT INTO orders (user_id, amount, status) VALUES
|
||||
(1, 99.50, 'paid'),
|
||||
(1, 12.00, 'pending'),
|
||||
(2, 250.00, 'paid'),
|
||||
(3, 8.80, 'cancelled'),
|
||||
(5, 41.20, 'paid');
|
||||
|
||||
INSERT INTO order_items (order_id, sku, qty, price) VALUES
|
||||
(1, 'SKU-A', 1, 99.50),
|
||||
(2, 'SKU-B', 2, 6.00),
|
||||
(3, 'SKU-C', 5, 50.00),
|
||||
(4, 'SKU-D', 1, 8.80),
|
||||
(5, 'SKU-E', 2, 20.60);
|
||||
@@ -0,0 +1,40 @@
|
||||
IF DB_ID('demo') IS NULL CREATE DATABASE demo;
|
||||
GO
|
||||
USE demo;
|
||||
GO
|
||||
IF OBJECT_ID('dbo.users','U') IS NOT NULL DROP TABLE dbo.order_items;
|
||||
IF OBJECT_ID('dbo.orders','U') IS NOT NULL DROP TABLE dbo.orders;
|
||||
IF OBJECT_ID('dbo.users','U') IS NOT NULL DROP TABLE dbo.users;
|
||||
GO
|
||||
CREATE TABLE dbo.users (
|
||||
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||
name NVARCHAR(64) NOT NULL,
|
||||
email NVARCHAR(128) NULL,
|
||||
status TINYINT NOT NULL DEFAULT 1,
|
||||
created_at DATETIME2 DEFAULT SYSUTCDATETIME()
|
||||
);
|
||||
CREATE TABLE dbo.orders (
|
||||
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
amount DECIMAL(12,2) NOT NULL DEFAULT 0,
|
||||
status NVARCHAR(16) NOT NULL DEFAULT 'pending',
|
||||
created_at DATETIME2 DEFAULT SYSUTCDATETIME()
|
||||
);
|
||||
CREATE TABLE dbo.order_items (
|
||||
id INT IDENTITY(1,1) PRIMARY KEY,
|
||||
order_id INT NOT NULL,
|
||||
sku NVARCHAR(64) NOT NULL,
|
||||
qty INT NOT NULL DEFAULT 1,
|
||||
price DECIMAL(12,2) NOT NULL DEFAULT 0
|
||||
);
|
||||
INSERT INTO dbo.users (name, email, status) VALUES
|
||||
(N'alice', N'alice@demo.local', 1),
|
||||
(N'bob', N'bob@demo.local', 1),
|
||||
(N'carol', N'carol@demo.local', 1),
|
||||
(N'dave', N'dave@demo.local', 0),
|
||||
(N'erin', N'erin@demo.local', 1);
|
||||
INSERT INTO dbo.orders (user_id, amount, status) VALUES
|
||||
(1, 99.50, N'paid'), (1, 12.00, N'pending'), (2, 250.00, N'paid'), (3, 8.80, N'cancelled'), (5, 41.20, N'paid');
|
||||
INSERT INTO dbo.order_items (order_id, sku, qty, price) VALUES
|
||||
(1, N'SKU-A', 1, 99.50), (2, N'SKU-B', 2, 6.00), (3, N'SKU-C', 5, 50.00), (4, N'SKU-D', 1, 8.80), (5, N'SKU-E', 2, 20.60);
|
||||
GO
|
||||
@@ -0,0 +1,53 @@
|
||||
CREATE DATABASE IF NOT EXISTS demo DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
USE demo;
|
||||
|
||||
DROP TABLE IF EXISTS order_items;
|
||||
DROP TABLE IF EXISTS orders;
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
||||
CREATE TABLE users (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
name VARCHAR(64) NOT NULL,
|
||||
email VARCHAR(128) NULL,
|
||||
status TINYINT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE orders (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
user_id INT NOT NULL,
|
||||
amount DECIMAL(12,2) NOT NULL DEFAULT 0,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_orders_user (user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE order_items (
|
||||
id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
order_id INT NOT NULL,
|
||||
sku VARCHAR(64) NOT NULL,
|
||||
qty INT NOT NULL DEFAULT 1,
|
||||
price DECIMAL(12,2) NOT NULL DEFAULT 0,
|
||||
INDEX idx_items_order (order_id)
|
||||
);
|
||||
|
||||
INSERT INTO users (name, email, status) VALUES
|
||||
('alice', 'alice@demo.local', 1),
|
||||
('bob', 'bob@demo.local', 1),
|
||||
('carol', 'carol@demo.local', 1),
|
||||
('dave', 'dave@demo.local', 0),
|
||||
('erin', 'erin@demo.local', 1);
|
||||
|
||||
INSERT INTO orders (user_id, amount, status) VALUES
|
||||
(1, 99.50, 'paid'),
|
||||
(1, 12.00, 'pending'),
|
||||
(2, 250.00, 'paid'),
|
||||
(3, 8.80, 'cancelled'),
|
||||
(5, 41.20, 'paid');
|
||||
|
||||
INSERT INTO order_items (order_id, sku, qty, price) VALUES
|
||||
(1, 'SKU-A', 1, 99.50),
|
||||
(2, 'SKU-B', 2, 6.00),
|
||||
(3, 'SKU-C', 5, 50.00),
|
||||
(4, 'SKU-D', 1, 8.80),
|
||||
(5, 'SKU-E', 2, 20.60);
|
||||
@@ -0,0 +1,43 @@
|
||||
BEGIN EXECUTE IMMEDIATE 'DROP TABLE order_items PURGE'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;
|
||||
/
|
||||
BEGIN EXECUTE IMMEDIATE 'DROP TABLE orders PURGE'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;
|
||||
/
|
||||
BEGIN EXECUTE IMMEDIATE 'DROP TABLE users PURGE'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;
|
||||
/
|
||||
CREATE TABLE users (
|
||||
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
name VARCHAR2(64) NOT NULL,
|
||||
email VARCHAR2(128),
|
||||
status NUMBER(3) DEFAULT 1 NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT SYSTIMESTAMP
|
||||
);
|
||||
CREATE TABLE orders (
|
||||
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
user_id NUMBER NOT NULL,
|
||||
amount NUMBER(12,2) DEFAULT 0 NOT NULL,
|
||||
status VARCHAR2(16) DEFAULT 'pending' NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT SYSTIMESTAMP
|
||||
);
|
||||
CREATE TABLE order_items (
|
||||
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
||||
order_id NUMBER NOT NULL,
|
||||
sku VARCHAR2(64) NOT NULL,
|
||||
qty NUMBER DEFAULT 1 NOT NULL,
|
||||
price NUMBER(12,2) DEFAULT 0 NOT NULL
|
||||
);
|
||||
INSERT INTO users (name, email, status) VALUES ('alice','alice@demo.local',1);
|
||||
INSERT INTO users (name, email, status) VALUES ('bob','bob@demo.local',1);
|
||||
INSERT INTO users (name, email, status) VALUES ('carol','carol@demo.local',1);
|
||||
INSERT INTO users (name, email, status) VALUES ('dave','dave@demo.local',0);
|
||||
INSERT INTO users (name, email, status) VALUES ('erin','erin@demo.local',1);
|
||||
INSERT INTO orders (user_id, amount, status) VALUES (1,99.50,'paid');
|
||||
INSERT INTO orders (user_id, amount, status) VALUES (1,12.00,'pending');
|
||||
INSERT INTO orders (user_id, amount, status) VALUES (2,250.00,'paid');
|
||||
INSERT INTO orders (user_id, amount, status) VALUES (3,8.80,'cancelled');
|
||||
INSERT INTO orders (user_id, amount, status) VALUES (5,41.20,'paid');
|
||||
INSERT INTO order_items (order_id, sku, qty, price) VALUES (1,'SKU-A',1,99.50);
|
||||
INSERT INTO order_items (order_id, sku, qty, price) VALUES (2,'SKU-B',2,6.00);
|
||||
INSERT INTO order_items (order_id, sku, qty, price) VALUES (3,'SKU-C',5,50.00);
|
||||
INSERT INTO order_items (order_id, sku, qty, price) VALUES (4,'SKU-D',1,8.80);
|
||||
INSERT INTO order_items (order_id, sku, qty, price) VALUES (5,'SKU-E',2,20.60);
|
||||
COMMIT;
|
||||
@@ -0,0 +1,32 @@
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(64) NOT NULL,
|
||||
email VARCHAR(128),
|
||||
status SMALLINT NOT NULL DEFAULT 1,
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS orders (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
amount NUMERIC(12,2) NOT NULL DEFAULT 0,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'pending',
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS order_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
order_id INT NOT NULL,
|
||||
sku VARCHAR(64) NOT NULL,
|
||||
qty INT NOT NULL DEFAULT 1,
|
||||
price NUMERIC(12,2) NOT NULL DEFAULT 0
|
||||
);
|
||||
TRUNCATE order_items, orders, users RESTART IDENTITY;
|
||||
INSERT INTO users (name, email, status) VALUES
|
||||
('alice', 'alice@demo.local', 1),
|
||||
('bob', 'bob@demo.local', 1),
|
||||
('carol', 'carol@demo.local', 1),
|
||||
('dave', 'dave@demo.local', 0),
|
||||
('erin', 'erin@demo.local', 1);
|
||||
INSERT INTO orders (user_id, amount, status) VALUES
|
||||
(1, 99.50, 'paid'), (1, 12.00, 'pending'), (2, 250.00, 'paid'), (3, 8.80, 'cancelled'), (5, 41.20, 'paid');
|
||||
INSERT INTO order_items (order_id, sku, qty, price) VALUES
|
||||
(1, 'SKU-A', 1, 99.50), (2, 'SKU-B', 2, 6.00), (3, 'SKU-C', 5, 50.00), (4, 'SKU-D', 1, 8.80), (5, 'SKU-E', 2, 20.60);
|
||||
@@ -0,0 +1,31 @@
|
||||
DROP TABLE IF EXISTS order_items;
|
||||
DROP TABLE IF EXISTS orders;
|
||||
DROP TABLE IF EXISTS users;
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT,
|
||||
status INTEGER NOT NULL DEFAULT 1,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE TABLE orders (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
amount REAL NOT NULL DEFAULT 0,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE TABLE order_items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
order_id INTEGER NOT NULL,
|
||||
sku TEXT NOT NULL,
|
||||
qty INTEGER NOT NULL DEFAULT 1,
|
||||
price REAL NOT NULL DEFAULT 0
|
||||
);
|
||||
INSERT INTO users (name, email, status) VALUES
|
||||
('alice','alice@demo.local',1),('bob','bob@demo.local',1),('carol','carol@demo.local',1),
|
||||
('dave','dave@demo.local',0),('erin','erin@demo.local',1);
|
||||
INSERT INTO orders (user_id, amount, status) VALUES
|
||||
(1,99.50,'paid'),(1,12.00,'pending'),(2,250.00,'paid'),(3,8.80,'cancelled'),(5,41.20,'paid');
|
||||
INSERT INTO order_items (order_id, sku, qty, price) VALUES
|
||||
(1,'SKU-A',1,99.50),(2,'SKU-B',2,6.00),(3,'SKU-C',5,50.00),(4,'SKU-D',1,8.80),(5,'SKU-E',2,20.60);
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# 已废弃一次性全开脚本。请用:
|
||||
# ./dbctl.sh up mysql
|
||||
# 详见 README.md
|
||||
echo "请使用 ./dbctl.sh up <mysql|mariadb|postgres|mssql|oracle> (一次只开一个)" >&2
|
||||
exit 1
|
||||
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"verdict": "通过",
|
||||
"pass": [
|
||||
"未执行时显示「执行」",
|
||||
"未执行时无「取消当前查询」",
|
||||
"执行中出现「取消」",
|
||||
"取消后出现「已取消」",
|
||||
"取消后恢复「执行」",
|
||||
"取消后可再跑",
|
||||
"Go errMsg(Canceled)=已取消 单测已绿"
|
||||
],
|
||||
"fail": [],
|
||||
"notes": [
|
||||
"inputCount=6",
|
||||
"afterConnect=OpsxDB 客户端 连接 新建连接 新建查询 历史 快捷键 cancel-reg-mysql AI 浅色 连接 + 分组 ▾ 默认 1 MySQLcancel-reg-mysql 对象 刷新 ▸ demo ▸ information_schema ▸ mysql ▸ performance_schema ▸ sys 查询 1 + 执行 格式化 执行计划 存书签 书签 ⌘/Ctrl+Enter 选"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 36 KiB |
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"verdict": "通过",
|
||||
"pass": [
|
||||
"MySQL 端口 3306",
|
||||
"PostgreSQL 端口 5432",
|
||||
"PostgreSQL 默认 postgres",
|
||||
"SQL Server 端口 1433",
|
||||
"SQL Server 默认 master",
|
||||
"Oracle 端口 1521",
|
||||
"Oracle 默认 ORCL",
|
||||
"Redis 端口 6379",
|
||||
"Redis常规无DB索引",
|
||||
"服务端失败前缀 SSH:/数据库:"
|
||||
],
|
||||
"fail": [],
|
||||
"notes": [],
|
||||
"priorRedisSshPassCount": 25,
|
||||
"priorFails": [
|
||||
"选不中 MySQL",
|
||||
"选不中 PostgreSQL",
|
||||
"选不中 SQL Server",
|
||||
"选不中 Oracle",
|
||||
"locator.click: Timeout 12000ms exceeded.\nCall log:\n - waiting for getByText('Redis', { exact: true }).first()\n - locator resolved to <div class=\"truncate text-[14px] font-semibold leading-tight\">Redis</div>\n - attempting click action\n 2 × waiting for element to be visible, enabled and stable\n - element is visible, enabled and stable\n - scrolling into view if needed\n - done scrolling\n - <div aria-modal=\"true\" role=\"alertdialog\" aria-labelledby=\"notify-title-1fc21b9b-31"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"verdict": "有缺陷",
|
||||
"pass": [
|
||||
"Redis常规「名称」",
|
||||
"Redis常规「主机」",
|
||||
"Redis常规「端口」",
|
||||
"Redis常规「密码」",
|
||||
"Redis常规「用户名」",
|
||||
"Redis常规「分隔符」",
|
||||
"常规无 DB 序号",
|
||||
"常规不可见 DB 索引",
|
||||
"密码可显隐",
|
||||
"Sentinel/Cluster 禁用",
|
||||
"Redis 端口 6379",
|
||||
"高级有 DB 索引",
|
||||
"Tab 常规",
|
||||
"Tab 高级",
|
||||
"Tab SSL",
|
||||
"Tab SSH",
|
||||
"SSH 开关",
|
||||
"SSH SSH 主机",
|
||||
"SSH SSH 端口",
|
||||
"SSH SSH 用户",
|
||||
"SSH 认证方式",
|
||||
"测试连接",
|
||||
"取消",
|
||||
"保存",
|
||||
"保存并连接"
|
||||
],
|
||||
"fail": [
|
||||
"选不中 MySQL",
|
||||
"选不中 PostgreSQL",
|
||||
"选不中 SQL Server",
|
||||
"选不中 Oracle",
|
||||
"locator.click: Timeout 12000ms exceeded.\nCall log:\n - waiting for getByText('Redis', { exact: true }).first()\n - locator resolved to <div class=\"truncate text-[14px] font-semibold leading-tight\">Redis</div>\n - attempting click action\n 2 × waiting for element to be visible, enabled and stable\n - element is visible, enabled and stable\n - scrolling into view if needed\n - done scrolling\n - <div aria-modal=\"true\" role=\"alertdialog\" aria-labelledby=\"notify-title-1fc21b9b-31"
|
||||
],
|
||||
"notes": [
|
||||
"测连未触发分层文案"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"verdict": "有缺陷",
|
||||
"pass": [
|
||||
"DB索引占位 0–15 database index",
|
||||
"DB索引拒绝16(当前=)",
|
||||
"DB索引可填3"
|
||||
],
|
||||
"fail": [
|
||||
"选不中 MySQL",
|
||||
"选不中 PostgreSQL",
|
||||
"选不中 SQL Server",
|
||||
"选不中 Oracle",
|
||||
"选不中 Redis",
|
||||
"locator.click: Timeout 10000ms exceeded.\nCall log:\n - waiting for getByText('SSH', { exact: true }).first()\n",
|
||||
"源码无分层前缀"
|
||||
],
|
||||
"notes": [
|
||||
"placeholders=[\"0–15(database index)\",\"mysql://root:pass@127.0.0.1:3306/demo\"]"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 67 KiB |
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"verdict": "有缺陷",
|
||||
"passCount": 2,
|
||||
"failCount": 4,
|
||||
"pass": [
|
||||
"Redis键过滤框出现",
|
||||
"2-空结果"
|
||||
],
|
||||
"fail": [
|
||||
"1-键列表不足 0 :: OpsxDB 客户端 连接 新建连接 新建查询 历史 快捷键 redis-keys-reg 隐藏 AI 浅色 连接 + 分组 ▾ 默认 1 Redisredis-keys-reg 对象 刷新 应用 ▸ 0 ▸ 键6 ▸ 1 ▸ 2 ▸ 3 ▸ 4 ▸ 5 ▸ 6 ▸ 7 ▸ 8 ▸ 9 ▸ 10 ▸ 11 ▸ 12 ▸ 13 ▸ 14 ▸ 15 查询 1 + 执行 格式化 执行计划 存书签 书签 ⌘/Ctrl+Enter 选区或当前语句;多语句出多结果 redis-keys-reg · Redis 1 SELECT 1 AS ok; 数据 结构 计划 还没有结果 写一条 SQL,⌘/Ctrl+",
|
||||
"2-过滤异常",
|
||||
"3-无str:hello",
|
||||
"locator.click: Timeout 18000ms exceeded.\nCall log:\n - waiting for getByText('hash:user').first()\n - locator resolved to <span class=\"truncate\">hash:user</span>\n - attempting click action\n 2 × waiting for element to be visible, enabled and stable\n - element is not visible\n - retrying click action\n - waiting 20ms\n 2 × waiting for element to be visible, enabled and stable\n - element is not visible\n - retrying click acti"
|
||||
],
|
||||
"notes": [
|
||||
"ws=OpsxDB 客户端 连接 新建连接 新建查询 历史 快捷键 redis-keys-reg 隐藏 AI 浅色 连接 + 分组 ▾ 默认 1 Redisredis-keys-reg ✎ × 对象 刷新 应用 ▸ 0 ▸ 1 ▸ 2 ▸ 3 ▸ 4 ▸ 5 ▸ 6 ▸ 7 ▸ 8 ▸ 9 ▸ 10 ▸ 11 ▸ 12 ▸ 13 ▸ 14 ▸ 15 查询 1 + 执行 格式化 执行计划 存书签 书签 ⌘/Ctrl+Enter 选区或当前语句;",
|
||||
"treeBtns=3",
|
||||
"类型可能缩写"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"verdict": "通过",
|
||||
"pass": [
|
||||
"UI三模式select",
|
||||
"require测连失败可读",
|
||||
"skip-verify测连成功",
|
||||
"verify-ca缺文件可读",
|
||||
"关SSL明文成功"
|
||||
],
|
||||
"fail": [],
|
||||
"notes": [
|
||||
"requireUI=连接 连接列表 常规 高级 SSL SSH SSL 使用 SSL 模式 require(加密) skip-verify(跳过证书校验) verify-ca(校验 CA) CA 证书 客户端证书 客户端密钥 仅加密传输;路径可留空。verify-",
|
||||
"vcUI=返回 MySQL 可连接 连接列表 常规 高级 SSL SSH SSL 使用 SSL 模式 require(加密) skip-verify(跳过证书校验) verify-ca(校验 CA) CA 证书 客户端证书 客户端密钥 校验服务端证书链;请填写 CA 证书路径。客户端证书/密钥可选。 数据库: 读取 CA 证书失败 (/tmp/no-such-ca.pem): open /tmp/no-such-ca.pem: no such file or directory 测试连接 取消 保存 保存并连接 ! 错误 操作失败 ✕ 数据库: 读取 CA 证书失",
|
||||
"验收前发现:8788旧进程(01:21)未含SSL,已./run.sh restart重编后再测"
|
||||
],
|
||||
"gaps": [
|
||||
"P1:MSSQL自定义CA→系统信任",
|
||||
"P1:Oracle仅开关无客户端证书"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"verdict": "有缺陷",
|
||||
"passCount": 22,
|
||||
"failCount": 1,
|
||||
"pass": [
|
||||
"3-MySQL:使用SSL开关",
|
||||
"3-模式:require",
|
||||
"3-模式:skip-verify",
|
||||
"3-模式:verify-ca",
|
||||
"3-证书路径字段",
|
||||
"3-SQLite禁用SSL",
|
||||
"3-Redis模式齐",
|
||||
"3-PostgreSQL模式齐",
|
||||
"3-SQL Server模式齐",
|
||||
"3-Oracle有SSL开关",
|
||||
"4-后端tls.go",
|
||||
"4-后端mysql.go",
|
||||
"4-后端postgres.go",
|
||||
"4-后端mssql.go",
|
||||
"4-后端redis.go",
|
||||
"4-后端oracle.go",
|
||||
"4-go test ./internal/db 绿",
|
||||
"5-开SSL失败可读(TLS类)",
|
||||
"5-关SSL明文成功",
|
||||
"5-保存含skip-verify",
|
||||
"5-CA路径已落库",
|
||||
"4-verify-ca需CA有校验"
|
||||
],
|
||||
"fail": [
|
||||
"3-无select"
|
||||
],
|
||||
"notes": [
|
||||
"sslOnFail=返回 MySQL 可连接 连接列表 常规 高级 SSL SSH SSL 使用 SSL 模式 require(加密) skip-verify(跳过证书校验) verify-ca(校验 CA) CA 证书 客户端证书 客户端密钥 仅加密传输;路径可留空。verify-ca 需填 CA。 连接成功。 测试连接 取消 保存 保存并连接",
|
||||
"sslOff=返回 MySQL 可连接 连接列表 常规 高级 SSL SSH SSL 使用 SSL 开启后可选择 require / skip-verify / verify-ca,并可选填证书路径。 连接成功。 测试连接 取消 保存 保存并连接",
|
||||
"ls=d\":\"586f8a4b-e28e-4d23-91a3-a1229aafea7e\",\"name\":\"ssl-persist-reg\",\"driver\":\"mysql\",\"host\":\"127.0.0.1\",\"port\":3306,\"user\":\"root\",\"password\":\"ox1.RGVtb0AxMjM=\",\"database\":\"\",\"ssl\":true,\"sslMode\":\"skip-verify\",\"sslCA\":\"/tmp/persist-ca.pem\",\"sslCert\":\"/tmp/client.pem\",\"sslKey\":\"/tmp/client.key\",\"servic"
|
||||
],
|
||||
"gaps": [
|
||||
"P1: Oracle仅开关未接客户端证书",
|
||||
"P1: MSSQL自定义CA暂走系统信任"
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 68 KiB |
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"verdict": "通过",
|
||||
"pass": [
|
||||
"后端挂短提示",
|
||||
"提示含 ./run.sh 与 8788",
|
||||
"有重试",
|
||||
"有「最近」分区",
|
||||
"搜索无匹配空态",
|
||||
"有搜索框",
|
||||
"工具栏提示选区/当前语句",
|
||||
"格式化可点且编辑器有内容",
|
||||
"已发 ⌘Z(撤销路径)",
|
||||
"选区优先逻辑已单测覆盖",
|
||||
"空态文案干净",
|
||||
"列表含最近逻辑"
|
||||
],
|
||||
"fail": [],
|
||||
"notes": [
|
||||
"未抓到启动中(可能已过)",
|
||||
"重试后仍显示未就绪(路由可能仍拦截)"
|
||||
]
|
||||
}
|
||||
@@ -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 ]]
|
||||