dever-labs/mockly

GitHub: dever-labs/mockly

这是一款跨平台、支持多种协议(HTTP、gRPC、Redis 等)的 Mock 服务器,提供 Web UI 和故障注入功能,专为组件测试与 CI 集成设计。

Stars: 0 | Forks: 0

# Mockly **跨平台、多协议 mock 服务器** — HTTP、WebSocket、gRPC、GraphQL、TCP、Redis、SMTP 和 MQTT 合并为单一二进制文件,内置 Web UI、REST 管理 API、场景系统和故障注入。 [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/8f8be57439223314.svg)](https://github.com/dever-labs/mockly/actions/workflows/ci.yml) [![Latest release](https://img.shields.io/github/v/release/dever-labs/mockly)](https://github.com/dever-labs/mockly/releases/latest) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) ## 目录 - [功能](#features) - [快速开始](#quickstart) - [配置](#configuration) - [协议](#protocols) - [组件测试](#component-testing) - [场景](#scenarios) - [故障注入](#fault-injection) - [PATCH Mocks](#patch-mocks) - [预设配置](#preset-configs) - [CLI 参考](#cli-reference) - [管理 API 参考](#management-api-reference) - [客户端库](#client-libraries) - [CI 集成](#ci-integration) - [架构](#architecture) - [开发](#development) - [贡献](#contributing) - [许可证](#license) ## 功能 | 功能 | 详情 | |---|---| | **协议** | HTTP, WebSocket, gRPC, GraphQL, TCP, Redis, SMTP, MQTT | | **请求匹配** | Method + path(精确 / 通配符 / 正则),headers,query params,JSON body 字段 | | **响应序列** | 每次连续调用返回不同的响应 — 循环、保持最后一个或用尽后返回 404 | | **响应控制** | 状态码、headers、body、人工延迟 | | **模板响应** | 响应体中使用 Go 模板语法(`{{now}}`、`{{.body}}` 等) | | **状态条件** | 仅当运行时状态变量匹配时触发 mock | | **场景** | 命名的 mock patch 集合 — 通过 API 或 CLI 原子激活/停用 | | **全局故障注入** | 对所有请求施加延迟、状态覆盖和概率性错误率 | | **单 mock 故障注入** | 单个 mock 上的故障字段 — 独立于全局故障 | | **调用验证** | 跟踪每个 mock 被命中的次数;阻塞直到达到预期次数 | | **PATCH mocks** | 在运行时仅更改特定的响应字段,无需替换整个 mock | | **预设配置** | 针对 Keycloak、Authelia、OAuth2、GitHub、Stripe、OpenAI、Slack、Twilio、SendGrid 的即插即用 YAML 配置 | | **Web UI** | 由二进制文件自身提供服务 — 无需单独安装 | | **管理 API** | 40+ REST 端点,覆盖所有协议、场景、故障、状态、日志和调用计数 | | **实时请求日志** | 通过 SSE 实时流式传输到 UI | | **CI 友好** | 零依赖、单一二进制、YAML 配置、Docker 镜像 | ## 快速开始 ### 下载 从 [releases page](https://github.com/dever-labs/mockly/releases) 获取适用于你平台的二进制文件,或从源码构建: ``` git clone https://github.com/dever-labs/mockly cd mockly make build # builds UI + Go binary ``` ### 使用配置文件运行 ``` mockly start --config mockly.yaml ``` 打开 `http://localhost:9091` 访问 Web UI,或在同一端口调用管理 API。 ### 运行预设 ``` mockly preset use keycloak # starts Mockly pre-loaded with Keycloak endpoints mockly preset list # list all available presets mockly preset show stripe # print the preset YAML ``` ## 配置 Mockly 由 YAML 配置文件驱动。每个部分都是可选的。 ``` mockly: api: port: 9091 # Management API + Web UI port (default: 9091) protocols: http: enabled: true port: 8080 mocks: - id: list-users request: method: GET path: /api/users response: status: 200 headers: Content-Type: application/json body: '[{"id":1,"name":"Alice"}]' delay: 50ms websocket: enabled: true port: 8081 mocks: - id: echo path: /ws/echo on_message: match: ping respond: pong grpc: enabled: true port: 50051 services: - name: users mocks: - id: get-user method: GetUser response: body: '{"id":"1","name":"Alice"}' graphql: enabled: true port: 8082 path: /graphql mocks: - id: get-user operation_type: query operation_name: GetUser response: user: id: "1" name: Alice tcp: enabled: true port: 8083 mocks: - id: hello pattern: "HELLO" response: "WORLD\n" redis: enabled: true port: 6379 mocks: - id: get-session command: GET key: "session:*" response: type: bulk value: '{"userId":"abc"}' smtp: enabled: true port: 2525 domain: mockly.local rules: - id: accept-all action: accept mqtt: enabled: true port: 1883 mocks: - id: sensor-ack topic: "sensors/+" response: topic: "sensors/ack" payload: '{"ok":true}' scenarios: - id: auth-down name: Auth Service Down description: Simulate auth outage — all token endpoints return 503 patches: - mock_id: list-users status: 503 body: '{"error":"auth unavailable"}' ``` ### 路径匹配 | 模式 | 匹配 | |---|---| | `/api/users` | 精确匹配 | | `/api/*` | 任何以 `/api/` 开头的路径 | | `re:^/users/\d+$` | 正则 — 任何 `/users/` | ### 模板响应 响应体作为 Go 模板渲染。内置函数: | 函数 | 示例 | 描述 | |---|---|---| | `{{now}}` | `2024-01-15T10:30:00Z` | 当前 UTC 时间(RFC3339) | | `{{date "2006-01-02"}}` | `2024-01-15` | Go 格式的当前日期 | | `{{date_add "2006-01-02" "-7d"}}` | `2024-01-08` | 带持续时长偏移的日期 | | `{{uuid}}` | `550e8400-e29b-41d4-a716-446655440000` | 随机 UUID v4 | | `{{rand_int 1 100}}` | `42` | [min, max] 范围内的随机整数 | | `{{rand_float 0.0 1.0 2}}` | `0.73` | 带有 N 位小数的随机浮点数 | | `{{rand_string 8}}` | `aB3xKp7m` | 随机字母数字字符串 | | `{{rand_string 8 "hex"}}` | `3f9a1c2b` | 字符集:`alpha`、`lower`、`upper`、`numeric`、`hex`、`alphanumeric` 或自定义 | | `{{rand_bool}}` | `true` | 随机布尔值 | | `{{pick "a" "b" "c"}}` | `b` | 随机选取给定值之一 | | `{{fake "name"}}` | `Alice Smith` | 伪造全名 | | `{{fake "email"}}` | `alice.smith@example.com` | 伪造邮箱 | | `{{fake "phone"}}` | `+1-555-0142` | 伪造电话号码 | | `{{fake "company"}}` | `Apex Labs` | 伪造公司名称 | | `{{fake "city"}}` | `Berlin` | 伪造城市 | | `{{fake "country"}}` | `Germany` | 伪造国家 | | `{{fake "street"}}` | `42 Main St` | 伪造街道地址 | | `{{fake "zip"}}` | `10115` | 伪造邮政编码 | | `{{fake "ip"}}` | `192.168.1.42` | 伪造 IPv4 | | `{{fake "ipv6"}}` | `2001:db8::1a2b:3c4d` | 伪造 IPv6 | | `{{fake "url"}}` | `https://apex.io/api/lorem` | 伪造 URL | | `{{fake "username"}}` | `alice42` | 伪造用户名 | | `{{fake "useragent"}}` | `Mozilla/5.0 …` | 随机 User-Agent 字符串 | | `{{fake "word"}}` | `lorem` | 单个 lorem ipsum 单词 | | `{{fake "sentence"}}` | `lorem ipsum dolor sit amet` | 短 lorem ipsum 短语 | | `{{seq "counter"}}` | `1`, `2`, `3`, … | 按命名计数器自动递增的整数 | | `{{lorem 5}}` | `lorem ipsum dolor sit amet` | N 个 lorem ipsum 单词 | | `{{upper "hello"}}` | `HELLO` | 大写字符串 | | `{{lower "WORLD"}}` | `world` | 小写字符串 | | `{{.body}}` | *(请求体)* | 传入的请求体 | | `{{.headers.X-Foo}}` | *(header 值)* | 传入的请求 header | | `{{state "key"}}` | *(状态值)* | 来自运行时状态存储的值 | **序列计数器**(`{{seq "name"}}`)会通过 `POST /api/reset` 或 `mockly reset` 重置为零。 示例 — 在每次请求时生成逼真的用户对象: ``` response: status: 200 headers: Content-Type: application/json body: | { "id": "{{uuid}}", "name": "{{fake "name"}}", "email": "{{fake "email"}}", "role": "{{pick "user" "admin" "viewer"}}", "score": {{rand_float 0 100 1}}, "created_at": "{{now}}" } ``` ## 协议 ### HTTP 完整的 HTTP mock 服务器。匹配 method + path(精确/通配符/正则)、可选 query params、header 匹配、JSON body 字段匹配和状态条件。 ``` protocols: http: enabled: true port: 8080 mocks: - id: create-user request: method: POST path: /users headers: Authorization: "Bearer *" response: status: 201 body: '{"id":"{{uuid}}"}' headers: Content-Type: application/json delay: 20ms ``` #### Query 参数匹配 ``` - id: admin-users request: method: GET path: /users query: role: admin # exact match page: "*" # any value (wildcard) response: status: 200 body: '[{"id":1,"role":"admin"}]' ``` #### JSON body 字段匹配 使用点符号路径匹配 JSON body 中任意位置的字段: ``` - id: gbp-payment request: method: POST path: /payments body_json: currency: GBP # exact "user.tier": premium # nested: {"user":{"tier":"premium"}} "items.0.sku": "*" # any SKU (wildcard) response: status: 200 body: '{"ok":true}' ``` #### 响应序列 每次连续调用返回不同的响应。适用于模拟瞬时错误或分页。 ``` - id: flaky-service request: method: GET path: /data sequence: - status: 503 body: '{"error":"unavailable"}' - status: 503 body: '{"error":"unavailable"}' - status: 200 body: '{"data":"ok"}' sequence_exhausted: hold_last # hold_last (default) | loop | not_found response: status: 200 body: '{"data":"ok"}' ``` | `sequence_exhausted` | 所有条目被消耗后的行为 | |---|---| | `hold_last` | 保持返回最后一个条目(默认) | | `loop` | 从第一个条目重新开始 | | `not_found` | 返回 404 | #### 单 mock 故障注入 每个 mock 都可以有自己的 `fault:` 块 — 独立于全局故障: ``` - id: slow-search request: method: GET path: /search fault: delay: 2s # add latency status_override: 429 # replace status code body: '{"error":"rate limited"}' error_rate: 0.5 # only apply 50% of the time (0 = always) response: status: 200 body: '[]' ``` ### WebSocket ``` protocols: websocket: enabled: true port: 8081 mocks: - id: ticker path: /ws/ticker on_connect: send: '{"type":"connected"}' on_message: match: subscribe respond: '{"type":"tick","price":42.0}' ``` ### gRPC 动态 gRPC mock — 无需编译 `.proto` 文件。使用原始编解码器拦截任何服务/方法调用。 ``` protocols: grpc: enabled: true port: 50051 services: - name: payments mocks: - id: charge method: Charge response: body: '{"success":true,"charge_id":"ch_123"}' ``` ### GraphQL 基于 HTTP 的 GraphQL mock。处理 `POST /graphql` 的 `application/json` 和 `application/graphql` 内容类型,以及带有 `query` 参数的 `GET` 请求。内省查询返回空 schema。 ``` protocols: graphql: enabled: true port: 8082 path: /graphql mocks: - id: create-post operation_type: mutation operation_name: CreatePost response: createPost: id: "{{uuid}}" title: Hello errors: [] ``` ### TCP 原始 TCP mock 服务器。将传入数据匹配为精确字符串、前缀通配符或正则。支持二进制协议的十六进制编码。 ``` protocols: tcp: enabled: true port: 8083 mocks: - id: ping pattern: "PING\r\n" response: "+PONG\r\n" - id: hex-response pattern: "re:^\\x02.*\\x03$" response_hex: "060000" ``` ### Redis RESP 协议 Redis mock。拦截任何 Redis 命令并返回可配置的响应。 ``` protocols: redis: enabled: true port: 6379 mocks: - id: auth command: AUTH response: type: string # string | bulk | integer | null | error | array value: "OK" - id: get-token command: GET key: "token:*" response: type: bulk value: "abc123" delay: 5ms ``` ### SMTP 捕获邮件并应用接受/拒绝规则的 SMTP 服务器。 ``` protocols: smtp: enabled: true port: 2525 domain: mockly.local rules: - id: reject-spam from: "*@spam.example.com" action: reject message: "550 spam not accepted" - id: accept-all action: accept ``` 捕获的邮件可在 `GET /api/emails` 查看。 ### MQTT 完整的 MQTT v3/v4/v5 broker(由 mochi-mqtt 驱动)。可配置的主题模式匹配,并自动发布响应。 ``` protocols: mqtt: enabled: true port: 1883 mocks: - id: command-ack topic: "devices/+/command" response: topic: "devices/+/ack" payload: '{"status":"ok"}' qos: 1 ``` 主题通配符:`+` 匹配单个段,`#` 匹配其下所有内容。 ## 组件测试 Mockly 专为 **组件测试** 设计 — 测试当依赖项返回错误、超时、意外数据或边缘情况响应时,你的应用程序如何表现。配置文件由依赖团队维护;使用团队只需加载它并切换场景。 ### 典型工作流 ``` dependency-service/ └── mockly/ ├── mockly.yaml # base happy-path mocks └── scenarios/ # optional split-out scenario files ├── auth-down.yaml └── payment-timeout.yaml ``` 你的测试: ``` // start mockly with the dependency's config // activate a scenario to simulate a failure // make requests to your app and assert it handles the error correctly // call the verification API to confirm your app called the right endpoints ``` ### 调用验证 检查你的应用命中 mock 的次数 — 无需抓取日志: ``` # POST /token 被调用了多少次? curl http://localhost:9091/api/calls/http/token-endpoint # 阻塞直到 mock 至少被调用 3 次(超时 5s) curl -X POST http://localhost:9091/api/calls/http/token-endpoint/wait \ -H 'Content-Type: application/json' \ -d '{"count":3,"timeout":"5s"}' # 重置单个 mock 的调用计数器 curl -X DELETE http://localhost:9091/api/calls/http/token-endpoint # 重置所有调用计数器 curl -X DELETE http://localhost:9091/api/calls/http ``` 来自 `GET /api/calls/http/{mockId}` 的响应: ``` { "mock_id": "token-endpoint", "count": 3, "calls": [ {"id": "...", "mock_id": "token-endpoint", "method": "POST", "path": "/token", "timestamp": "..."} ] } ``` ### 完整组件测试示例 ``` protocols: http: enabled: true port: 8080 mocks: # Happy path - id: get-token request: method: POST path: /oauth/token body_json: grant_type: client_credentials response: status: 200 body: '{"access_token":"{{uuid}}","expires_in":3600}' # Sequence: simulate token refresh after expiry - id: get-token-expiry-flow request: method: POST path: /oauth/token body_json: grant_type: refresh_token sequence: - status: 401 body: '{"error":"token_expired"}' - status: 200 body: '{"access_token":"new-token","expires_in":3600}' sequence_exhausted: hold_last response: status: 200 body: '{"access_token":"new-token","expires_in":3600}' scenarios: - id: auth-service-down name: Auth Service Down patches: - mock_id: get-token status: 503 body: '{"error":"service unavailable"}' - id: rate-limited name: Rate Limited patches: - mock_id: get-token status: 429 body: '{"error":"too_many_requests"}' ``` ## 场景 场景允许你预定义命名的 mock 覆盖,并随时激活/停用它们 — 非常适合在测试期间切换正常路径和故障模式。 ### 在配置中定义 ``` scenarios: - id: payment-timeout name: Payment Gateway Timeout patches: - mock_id: charge status: 504 body: '{"error":"timeout"}' delay: 5s - mock_id: refund disabled: true # Removes this endpoint entirely ``` ### 通过 CLI 控制 ``` mockly scenario list mockly scenario activate payment-timeout mockly scenario deactivate payment-timeout ``` ### 通过 API 控制 ``` # 激活 curl -X POST http://localhost:9091/api/scenarios/payment-timeout/activate # 停用 curl -X DELETE http://localhost:9091/api/scenarios/payment-timeout/activate # 列出激活项 curl http://localhost:9091/api/scenarios/active ``` ## 故障注入 注入全局故障以测试应用程序的弹性 — 无需触及单个 mock。 ``` # 为所有请求注入 100ms 延迟 mockly fault set --delay 100ms # 使 30% 的请求返回 503 mockly fault set --status 503 --rate 0.3 # 始终返回 429(速率限制) mockly fault set --status 429 # 移除故障 mockly fault clear ``` 或通过 API: ``` curl -X POST http://localhost:9091/api/fault \ -H 'Content-Type: application/json' \ -d '{"enabled":true,"delay":"100ms","status_override":503,"error_rate":0.3}' curl -X DELETE http://localhost:9091/api/fault ``` 故障字段: | 字段 | 类型 | 描述 | |---|---|---| | `enabled` | bool | 总开关 | | `delay` | duration | 在匹配之前为每个请求添加的延迟 | | `status_override` | int | 匹配后替换响应状态 | | `error_rate` | float | 覆盖触发的概率(0–1);0 = 总是 | ## PATCH Mocks 更改现有 mock 的单个字段,无需完全替换它: ``` curl -X PATCH http://localhost:9091/api/mocks/http/charge \ -H 'Content-Type: application/json' \ -d '{"response":{"status":500,"body":"{\"error\":\"internal\"}"}}' ``` ## 预设配置 Mockly 附带了针对常见服务的预构建 YAML 配置: | 预设 | 描述 | |---|---| | `keycloak` | Token 端点、JWKS、userinfo、内省 | | `authelia` | Auth 验证、session 端点 | | `oauth2` | 通用 OAuth2 流程(authorize、token、revoke) | | `github` | REST API:repos、issues、pull requests | | `stripe` | Charges、refunds、customers、payment intents | | `openai` | Chat completions、embeddings、models | | `slack` | Messages、channels、users、reactions | | `twilio` | SMS、calls、lookup | | `sendgrid` | Email send、templates、contacts | 每个预设还包含针对常见故障模式的内置场景(例如 `keycloak-unauthorized`、`stripe-card-declined`)。 ### 使用预设 ``` mockly preset use keycloak ``` ### 将预设导入你自己的配置 ``` mockly preset show keycloak > keycloak.yaml # 编辑 keycloak.yaml,然后: mockly start --config keycloak.yaml ``` ## CLI 参考 ``` mockly start [--config ] [--http-port ] [--api-port ] mockly apply --config mockly list mockly add http --method GET --path /foo --status 200 --body '{"ok":true}' mockly delete mockly status mockly reset mockly preset list | show | use mockly scenario list | show | activate | deactivate mockly fault set [--delay ] [--status ] [--rate ] | clear | show ``` ## 管理 API 参考 Base URL: `http://localhost:9091` ### 协议 | 方法 | 路径 | 描述 | |---|---|---| | `GET | `/api/protocols` | 列出所有协议状态 | | `GET` | `/api/health` | 健康检查 | ### HTTP Mocks | 方法 | 路径 | 描述 | |---|---|---| | `GET` | `/api/mocks/http` | 列出 HTTP mocks | | `POST` | `/api/mocks/http` | 创建 HTTP mock | | `PUT` | `/api/mocks/http/{id}` | 替换 HTTP mock | | `PATCH` | `/api/mocks/http/{id}` | 部分更新 HTTP mock | | `DELETE` | `/api/mocks/http/{id}` | 删除 HTTP mock | WebSocket (`/api/mocks/websocket`)、gRPC (`/api/mocks/grpc`)、GraphQL (`/api/mocks/graphql`)、TCP (`/api/mocks/tcp`)、Redis (`/api/mocks/redis`)、SMTP (`/api/mocks/smtp`)、MQTT (`/api/mocks/mqtt`) 同理。 ### 调用验证 (HTTP) | 方法 | 路径 | 描述 | |---|---|---| | `GET` | `/api/calls/http/{mockId}` | 获取 mock 的调用计数 + 日志条目 | | `POST` | `/api/calls/http/{mockId}/wait` | 阻塞直到 mock 被调用 N 次(body:`{"count":N,"timeout":"5s"}`) | | `DELETE` | `/api/calls/http/{mockId}` | 清除 mock 的日志条目 + 重置所有 HTTP 调用计数 | | `DELETE` | `/api/calls/http` | 清除所有 HTTP 日志条目并重置所有调用计数 | ### 邮箱收件箱 (SMTP) | 方法 | 路径 | 描述 | |---|---|---| | `GET` | `/api/emails` | 列出捕获的邮件 | | `DELETE` | `/api/emails` | 清空收件箱 | ### MQTT 消息 | 方法 | 路径 | 描述 | |---|---|---| | `GET` | `/api/mqtt/messages` | 列出捕获的 MQTT 消息 | | `DELETE` | `/api/mqtt/messages` | 清空消息存储 | ### 场景 | 方法 | 路径 | 描述 | |---|---|---| | `GET` | `/api/scenarios` | 列出所有场景 | | `POST` | `/api/scenarios` | 创建场景 | | `GET` | `/api/scenarios/active` | 列出活动场景 | | `GET` | `/api/scenarios/{id}` | 获取场景 | | `PUT` | `/api/scenarios/{id}` | 替换场景 | | `DELETE` | `/api/scenarios/{id}` | 删除场景 | | `POST` | `/api/scenarios/{id}/activate` | 激活场景 | | `DELETE` | `/api/scenarios/{id}/activate` | 停用场景 | ### 故障注入 | 方法 | 路径 | 描述 | |---|---|---| | `GET` | `/api/fault` | 获取当前故障配置 | | `POST` | `/api/fault` | 设置故障配置 | | `DELETE` | `/api/fault` | 清除故障 | ### 状态存储 | 方法 | 路径 | 描述 | |---|---|---| | `GET` | `/api/state` | 获取所有状态键 | | `POST` | `/api/state` | 设置状态键(JSON 对象) | | `DELETE` | `/api/state/{key}` | 删除状态键 | ### 日志 | 方法 | 路径 | 描述 | |---|---|---| | `GET` | `/api/logs` | 获取最近的日志条目 | | `DELETE` | `/api/logs` | 清除日志 | | `GET` | `/api/logs/stream` | 实时日志条目的 SSE 流 | ### 重置 | 方法 | 路径 | 描述 | |---|---|---| | `POST` | `/api/reset` | 将所有 mocks/状态/日志/故障/场景重置为配置默认值 | ## 客户端库 Mockly 提供官方客户端,为你管理进程生命周期、端口分配和管理 API — 让测试保持整洁和可移植。 | 语言 | 包 | 安装 | |---|---|---| | **Go** | `github.com/dever-labs/mockly/clients/go` | `go get github.com/dever-labs/mockly/clients/go` | | **Node.js / TypeScript** | `@dever-labs/mockly-driver` | `npm i -D @dever-labs/mockly-driver` | | **Java** | `io.github.dever-labs:mockly-driver` | 见下文 Maven/Gradle | | **.NET / C#** | `Mockly.Driver` | `dotnet add package Mockly.Driver` | | **Python** | `mockly-driver` | `pip install mockly-driver` | | **Rust** | `mockly-driver` | 在 `[dev-dependencies]` 中添加 `mockly-driver = "0.4"` | 所有客户端: - 自动查找或安装适用于当前平台的 Mockly 二进制文件 - 原子分配两个空闲端口(无 TOCTOU 竞争) - 端口冲突时重试启动最多 3 次 - 暴露相同的概念:`addMock`、`activateScenario`、`setFault`、`reset`、`stop` ### Go ``` import mocklydriver "github.com/dever-labs/mockly/clients/go" server, err := mocklydriver.Ensure(mocklydriver.Options{}, mocklydriver.InstallOptions{}) defer server.Stop() server.AddMock(mocklydriver.Mock{ ID: "get-user", Request: mocklydriver.Request{Method: "GET", Path: "/users/1"}, Response: mocklydriver.Response{Status: 200, Body: `{"id":1}`}, }) // server.HTTPBase = "http://127.0.0.1:" ``` [→ 完整 Go 文档](docs/clients/go.md) ### Node.js / TypeScript ``` import { MocklyServer } from '@dever-labs/mockly-driver' const server = await MocklyServer.ensure() await server.addMock({ id: 'get-user', request: { method: 'GET', path: '/users/1' }, response: { status: 200, body: '{"id":1}' }, }) // server.httpBase = "http://127.0.0.1:" await server.stop() ``` [→ 完整 Node.js 文档](docs/clients/node.md) ### Java ``` io.github.dever-labs mockly-driver 0.4.7 test ``` ``` try (MocklyServer server = MocklyServer.ensure(MocklyConfig.builder().build())) { server.addMock(Mock.builder("get-user", MockRequest.builder("GET", "/users/1").build(), MockResponse.builder(200).body("{\"id\":1}").build() ).build()); // server.httpBase = "http://127.0.0.1:" } ``` [→ 完整 Java 文档](docs/clients/java.md) ### .NET / C# ``` dotnet add package Mockly.Driver ``` ``` await using var server = await MocklyServer.CreateAsync(); await server.AddMockAsync(new Mock { Id = "get-user", Request = new MockRequest { Method = "GET", Path = "/users/1" }, Response = new MockResponse { Status = 200, Body = """{"id":1}""" }, }); // server.HttpBase = "http://127.0.0.1:" ``` [→ 完整 .NET 文档](docs/clients/dotnet.md) ### Python ``` pip install mockly-driver ``` ``` from mockly_driver import MocklyServer, Mock, MockRequest, MockResponse server = MocklyServer.ensure() server.add_mock(Mock( id="get-user", request=MockRequest(method="GET", path="/users/1"), response=MockResponse(status=200, body='{"id":1}'), )) # server.http_base = "http://127.0.0.1:" server.stop() ``` [→ 完整 Python 文档](docs/clients/python.md) ### Rust ``` [dev-dependencies] mockly-driver = "0.4" ``` ``` let mut server = MocklyServer::ensure(ServerOptions::default(), Default::default()).unwrap(); server.add_mock(&Mock { id: "get-user".into(), request: Request { method: "GET".into(), path: "/users/1".into(), ..Default::default() }, response: Response { status: 200, body: Some(r#"{"id":1}"#.into()), ..Default::default() }, }).unwrap(); // server.http_base = "http://127.0.0.1:" ``` [→ 完整 Rust 文档](docs/clients/rust.md) ## CI 集成 Mockly 是一个无运行时依赖的单一静态二进制文件 — 非常适合 CI。 ### GitHub Actions (composite action) ``` steps: - uses: actions/checkout@v5 - name: Start Mockly uses: dever-labs/mockly/.github/actions/setup-mockly@v0.4.7 with: version: v0.4.7 # pin to a specific version config: mockly.yaml # path to your config api-port: 9090 # management API port (default) - name: Run tests run: npm test ``` 该 action 自动: - 下载适用于 runner OS/arch 的正确二进制文件 - 在后台启动 mockly - 等待最多 30 秒直到服务器就绪 - 作业完成后终止进程 ### GitLab CI 包含模板并扩展 `.mockly-start` 作业: ``` include: - remote: 'https://raw.githubusercontent.com/dever-labs/mockly/main/.gitlab/mockly.yml' integration-tests: extends: .mockly-start variables: MOCKLY_VERSION: "v0.4.7" MOCKLY_CONFIG: "mockly.yaml" script: - ./run-tests.sh ``` 或将其作为 Docker 服务运行(无需安装二进制文件): ``` integration-tests: image: alpine:3.21 services: - name: ghcr.io/dever-labs/mockly:latest alias: mockly variables: # mount config via CI artifacts or inline variables: MOCKLY_URL: http://mockly:9090 script: - apk add --no-cache curl - curl "$MOCKLY_URL/api/protocols" - ./run-tests.sh ``` ### 任何 CI (安装脚本) ``` # 安装最新版本 curl -sSfL https://raw.githubusercontent.com/dever-labs/mockly/main/install.sh | bash # 或固定到特定版本 MOCKLY_VERSION=v0.2.0 \ curl -sSfL https://raw.githubusercontent.com/dever-labs/mockly/main/install.sh | bash # 在后台启动并等待就绪 mockly start -c mockly.yaml & until curl -sf http://localhost:9090/api/protocols; do sleep 1; done ``` ### Docker ``` # 使用本地配置运行 docker run --rm \ -v "$PWD/mockly.yaml:/config/mockly.yaml:ro" \ -p 8080:8080 -p 9090:9090 \ ghcr.io/dever-labs/mockly:latest # 或使用 docker compose docker compose up ``` ## 架构 ``` ┌──────────────────────────────────────────────────────────────────────────────────┐ │ Single Binary │ │ │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ Management API + Web UI :9091 │ │ │ │ CRUD mocks/rules · scenarios · fault · state · logs/SSE │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────┐ ┌─────────┐ ┌──────┐ ┌─────────┐ ┌─────┐ ┌───────┐ ┌──────┐ ┌──────┐ │ │ │ HTTP │ │WebSocket│ │ gRPC │ │GraphQL │ │ TCP │ │ Redis │ │ SMTP │ │ MQTT │ │ │ │:8080 │ │ :8081 │ │:50051│ │ :8082 │ │:8083│ │ :6379 │ │:2525 │ │:1883 │ │ │ └──────┘ └─────────┘ └──────┘ └─────────┘ └─────┘ └───────┘ └──────┘ └──────┘ │ │ │ │ Shared: State Store · Request Logger · Scenario Store │ └──────────────────────────────────────────────────────────────────────────────────┘ ``` ## 开发 ``` make build # build UI + Go binary make test # run unit + integration tests make test-e2e # run e2e tests (builds binary first) make lint # run golangci-lint make dev # hot-reload with air ``` 完整的设置说明、提交约定和 PR 流程请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。 ## 贡献 欢迎贡献 — 错误报告、功能请求、预设配置和代码。 在提交 pull request 之前,请阅读 [CONTRIBUTING.md](CONTRIBUTING.md)。 参与即表示你同意遵守 [行为准则](CODE_OF_CONDUCT.md)。 对于安全问题,请遵循 [SECURITY.md](
标签:API模拟, EVTX分析, GraphQL, gRPC, Mock服务器, Python工具, Redis, RESTful API, SMTP, SOC Prime, TCP, WebSocket, Web界面, 依赖分析, 内核驱动, 场景测试, 多协议, 开发工具, 提示词优化, 搜索引擎查询, 故障注入, 日志审计, 模拟数据, 测试工具, 组件测试, 网络协议, 请求拦截