fix web ui smoke and brand assets
@@ -0,0 +1,61 @@
|
||||
# Automation Step 1 Foundation Report
|
||||
|
||||
Date: 2026-06-29
|
||||
|
||||
## Scope
|
||||
|
||||
- Created the shared automated test workspace under `tests/`.
|
||||
- Added root test script entry points.
|
||||
- Added an idempotent fixed test data seed script at `prisma/seed-test.ts`.
|
||||
|
||||
## Changed Files
|
||||
|
||||
- `package.json`
|
||||
- `prisma/seed-test.ts`
|
||||
- `tests/README.md`
|
||||
- `tests/api/README.md`
|
||||
- `tests/web/README.md`
|
||||
- `tests/smoke/README.md`
|
||||
- `tests/fixtures/README.md`
|
||||
- `tests/reports/README.md`
|
||||
|
||||
## Script Entry Points
|
||||
|
||||
- `pnpm test:baseline`
|
||||
- `pnpm test:api`
|
||||
- `pnpm test:all-local`
|
||||
- `pnpm db:seed:test`
|
||||
|
||||
## Verification
|
||||
|
||||
| Check | Result | Notes |
|
||||
| --- | --- | --- |
|
||||
| `package.json` parse | PASS | JSON parsed successfully. |
|
||||
| `tsc --noEmit prisma/seed-test.ts` | PASS | Prisma unique keys and TypeScript types compile. |
|
||||
| `eslint prisma/seed-test.ts --max-warnings=0` | PASS | No lint violations. |
|
||||
| `pnpm db:seed:test` | BLOCKED | Script starts correctly but local MySQL is not reachable at `127.0.0.1:3306`. |
|
||||
|
||||
## Seed Data Coverage
|
||||
|
||||
- Test users and roles for admin, viewer, finance, quality, customer gateway, vendor gateway, active call, and audit flows.
|
||||
- Customer fixtures for normal balance and low balance scenarios.
|
||||
- Business prefixes `671` and `672`.
|
||||
- Vendor, primary/backup vendor gateways, codecs, prefix rewrite, forbidden period, caller rewrite pool.
|
||||
- Landing line group with weighted primary/backup gateway items.
|
||||
- Customer IP and SIP gateways, gateway IP, business prefix bindings, caller prefix, and policy.
|
||||
- Number library seed for city, mobile segment, area code, and carrier prefix rule.
|
||||
- Rated CDR, recording, sampling rule, and quality review samples.
|
||||
|
||||
## Current Blocker
|
||||
|
||||
Local database service is not running or not reachable:
|
||||
|
||||
```text
|
||||
Can't reach database server at `127.0.0.1:3306`
|
||||
```
|
||||
|
||||
After MySQL is available, rerun:
|
||||
|
||||
```powershell
|
||||
corepack pnpm@10.33.0 db:seed:test
|
||||
```
|
||||
@@ -0,0 +1,3 @@
|
||||
# Reports
|
||||
|
||||
Generated reports and run summaries can be saved here. Keep committed reports small and intentional.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Remote Auth, Session, and Permission Test Report
|
||||
|
||||
Date: 2026-06-29T05:05:54.328Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | captcha endpoint is public | status=200, duration=1787ms |
|
||||
| PASS | captcha returns id, SVG image, and expiry | captchaId=9de040cf-75c5-440f-a5cc-4bbf16d052c3, expiresAt=2026-06-29T05:10:43.316Z |
|
||||
| PASS | protected API rejects anonymous request | status=401, duration=1025ms |
|
||||
| PASS | login rejects invalid captcha | status=401, duration=1152ms |
|
||||
| PASS | invalid captcha returns AUTH_CAPTCHA_INVALID | code=AUTH_CAPTCHA_INVALID |
|
||||
| PASS | captcha answer can be parsed from SVG | length=5 |
|
||||
| PASS | login rejects invalid password with valid captcha | status=401, duration=489ms |
|
||||
| PASS | invalid credentials code is returned | code=AUTH_INVALID_CREDENTIALS |
|
||||
| PASS | login succeeds with valid captcha and password | status=200, duration=456ms |
|
||||
| PASS | login returns access token | tokenLength=296 |
|
||||
| PASS | login returns user profile and permissions | {"id":"usr_admin","username":"admin","displayName":"系统管理员","roles":["超级管理员"],"permissionCount":24} |
|
||||
| PASS | login sets HttpOnly refresh cookie | refresh cookie present |
|
||||
| PASS | bearer token can access protected dashboard summary | status=200, duration=402ms |
|
||||
| PASS | invalid bearer token is rejected | status=401, duration=790ms |
|
||||
| PASS | refresh rotates session and returns new token | status=200, duration=392ms |
|
||||
| PASS | refresh returns access token | tokenChanged=true |
|
||||
| PASS | refresh sets a rotated refresh cookie | rotated cookie present |
|
||||
| PASS | refreshed bearer token can access protected dashboard summary | status=200, duration=411ms |
|
||||
| PASS | logout revokes current refresh session | status=204, duration=399ms |
|
||||
| PASS | refresh after logout is rejected | status=401, duration=376ms |
|
||||
| PASS | admin account has non-empty permission set | permissionCount=24, roles=超级管理员 |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted.
|
||||
- This run uses the remote B service as a black-box API target.
|
||||
- Permission-denied 403 checks require a low-privilege account and are not asserted by this admin-only run.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Remote Auth, Session, and Permission Test Report
|
||||
|
||||
Date: 2026-06-29T05:09:44.031Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | captcha endpoint is public | status=200, duration=2229ms |
|
||||
| PASS | captcha returns id, SVG image, and expiry | captchaId=e003b59f-ddd2-4732-a0eb-8e7ff9e2a30e, expiresAt=2026-06-29T05:14:28.340Z |
|
||||
| PASS | protected API rejects anonymous request | status=401, duration=664ms |
|
||||
| PASS | login rejects invalid captcha | status=401, duration=375ms |
|
||||
| PASS | invalid captcha returns AUTH_CAPTCHA_INVALID | code=AUTH_CAPTCHA_INVALID |
|
||||
| PASS | captcha answer can be parsed from SVG | length=5 |
|
||||
| PASS | login rejects invalid password with valid captcha | status=401, duration=613ms |
|
||||
| PASS | invalid credentials code is returned | code=AUTH_INVALID_CREDENTIALS |
|
||||
| PASS | login succeeds with valid captcha and password | status=200, duration=581ms |
|
||||
| PASS | login returns access token | tokenLength=296 |
|
||||
| PASS | login returns user profile and permissions | {"id":"usr_admin","username":"admin","displayName":"系统管理员","roles":["超级管理员"],"permissionCount":24} |
|
||||
| PASS | login sets HttpOnly refresh cookie | refresh cookie present |
|
||||
| PASS | low-privilege role is created | status=201, duration=555ms |
|
||||
| PASS | low-privilege role only has dashboard.view | roleId=rol_1f4592370a1941cf860ff1afdc92, permissions=dashboard.view |
|
||||
| PASS | low-privilege user is created | status=201, duration=449ms |
|
||||
| PASS | low-privilege user is bound to low role | userId=usr_102e3dcda767449f9f288ec09e8b, roleIds=rol_1f4592370a1941cf860ff1afdc92 |
|
||||
| PASS | bearer token can access protected dashboard summary | status=200, duration=387ms |
|
||||
| PASS | invalid bearer token is rejected | status=401, duration=378ms |
|
||||
| PASS | refresh rotates session and returns new token | status=200, duration=391ms |
|
||||
| PASS | refresh returns access token | tokenChanged=true |
|
||||
| PASS | refresh sets a rotated refresh cookie | rotated cookie present |
|
||||
| PASS | refreshed bearer token can access protected dashboard summary | status=200, duration=383ms |
|
||||
| PASS | logout revokes current refresh session | status=204, duration=384ms |
|
||||
| PASS | refresh after logout is rejected | status=401, duration=825ms |
|
||||
| PASS | low-privilege captcha answer can be parsed from SVG | length=5 |
|
||||
| PASS | low-privilege user can login | status=200, duration=636ms |
|
||||
| PASS | low-privilege login returns dashboard.view only | {"id":"usr_102e3dcda767449f9f288ec09e8b","username":"codex.low","displayName":"Codex低权限测试用户","roles":["自动化低权限角色"],"permissionCount":1} |
|
||||
| PASS | low-privilege user can access allowed dashboard summary | status=200, duration=697ms |
|
||||
| PASS | low-privilege user is forbidden from users.manage endpoint | status=403, duration=1132ms |
|
||||
| PASS | admin account has non-empty permission set | permissionCount=24, roles=超级管理员 |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted.
|
||||
- This run uses the remote B service as a black-box API target.
|
||||
- The low-privilege role and user are created or updated through the admin API before RBAC assertions.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Remote Auth, Session, and Permission Test Report
|
||||
|
||||
Date: 2026-06-29T05:10:08.459Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | captcha endpoint is public | status=200, duration=2754ms |
|
||||
| PASS | captcha returns id, SVG image, and expiry | captchaId=ffef58d0-1acf-43f7-adf2-6a97bf64960d, expiresAt=2026-06-29T05:14:51.988Z |
|
||||
| PASS | protected API rejects anonymous request | status=401, duration=387ms |
|
||||
| PASS | login rejects invalid captcha | status=401, duration=857ms |
|
||||
| PASS | invalid captcha returns AUTH_CAPTCHA_INVALID | code=AUTH_CAPTCHA_INVALID |
|
||||
| PASS | captcha answer can be parsed from SVG | length=5 |
|
||||
| PASS | login rejects invalid password with valid captcha | status=401, duration=441ms |
|
||||
| PASS | invalid credentials code is returned | code=AUTH_INVALID_CREDENTIALS |
|
||||
| PASS | login succeeds with valid captcha and password | status=200, duration=455ms |
|
||||
| PASS | login returns access token | tokenLength=296 |
|
||||
| PASS | login returns user profile and permissions | {"id":"usr_admin","username":"admin","displayName":"系统管理员","roles":["超级管理员"],"permissionCount":24} |
|
||||
| PASS | login sets HttpOnly refresh cookie | refresh cookie present |
|
||||
| PASS | low-privilege role is updated | status=200, duration=400ms |
|
||||
| PASS | low-privilege role only has dashboard.view | roleId=rol_1f4592370a1941cf860ff1afdc92, permissions=dashboard.view |
|
||||
| FAIL | low-privilege user is updated | status=201, duration=583ms |
|
||||
| PASS | low-privilege user is bound to low role | userId=usr_102e3dcda767449f9f288ec09e8b, roleIds=rol_1f4592370a1941cf860ff1afdc92 |
|
||||
| PASS | bearer token can access protected dashboard summary | status=200, duration=430ms |
|
||||
| PASS | invalid bearer token is rejected | status=401, duration=379ms |
|
||||
| PASS | refresh rotates session and returns new token | status=200, duration=412ms |
|
||||
| PASS | refresh returns access token | tokenChanged=true |
|
||||
| PASS | refresh sets a rotated refresh cookie | rotated cookie present |
|
||||
| PASS | refreshed bearer token can access protected dashboard summary | status=200, duration=979ms |
|
||||
| PASS | logout revokes current refresh session | status=204, duration=531ms |
|
||||
| PASS | refresh after logout is rejected | status=401, duration=373ms |
|
||||
| PASS | low-privilege captcha answer can be parsed from SVG | length=5 |
|
||||
| PASS | low-privilege user can login | status=200, duration=709ms |
|
||||
| PASS | low-privilege login returns dashboard.view only | {"id":"usr_102e3dcda767449f9f288ec09e8b","username":"codex.low","displayName":"Codex低权限测试用户","roles":["自动化低权限角色"],"permissionCount":1} |
|
||||
| PASS | low-privilege user can access allowed dashboard summary | status=200, duration=572ms |
|
||||
| PASS | low-privilege user is forbidden from users.manage endpoint | status=403, duration=383ms |
|
||||
| PASS | admin account has non-empty permission set | permissionCount=24, roles=超级管理员 |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted.
|
||||
- This run uses the remote B service as a black-box API target.
|
||||
- The low-privilege role and user are created or updated through the admin API before RBAC assertions.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Remote Auth, Session, and Permission Test Report
|
||||
|
||||
Date: 2026-06-29T05:11:04.930Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | captcha endpoint is public | status=200, duration=2542ms |
|
||||
| PASS | captcha returns id, SVG image, and expiry | captchaId=3bae4958-534c-4c78-a720-24f0324c4afc, expiresAt=2026-06-29T05:15:46.682Z |
|
||||
| PASS | protected API rejects anonymous request | status=401, duration=390ms |
|
||||
| PASS | login rejects invalid captcha | status=401, duration=856ms |
|
||||
| PASS | invalid captcha returns AUTH_CAPTCHA_INVALID | code=AUTH_CAPTCHA_INVALID |
|
||||
| PASS | captcha answer can be parsed from SVG | length=5 |
|
||||
| PASS | login rejects invalid password with valid captcha | status=401, duration=1026ms |
|
||||
| PASS | invalid credentials code is returned | code=AUTH_INVALID_CREDENTIALS |
|
||||
| PASS | login succeeds with valid captcha and password | status=200, duration=452ms |
|
||||
| PASS | login returns access token | tokenLength=296 |
|
||||
| PASS | login returns user profile and permissions | {"id":"usr_admin","username":"admin","displayName":"系统管理员","roles":["超级管理员"],"permissionCount":24} |
|
||||
| PASS | login sets HttpOnly refresh cookie | refresh cookie present |
|
||||
| PASS | low-privilege role is updated | status=200, duration=1123ms |
|
||||
| PASS | low-privilege role only has dashboard.view | roleId=rol_1f4592370a1941cf860ff1afdc92, permissions=dashboard.view |
|
||||
| PASS | low-privilege user is updated | status=201, expected=200/201, duration=705ms |
|
||||
| PASS | low-privilege user is bound to low role | userId=usr_102e3dcda767449f9f288ec09e8b, roleIds=rol_1f4592370a1941cf860ff1afdc92 |
|
||||
| PASS | bearer token can access protected dashboard summary | status=200, duration=393ms |
|
||||
| PASS | invalid bearer token is rejected | status=401, duration=392ms |
|
||||
| PASS | refresh rotates session and returns new token | status=200, duration=392ms |
|
||||
| PASS | refresh returns access token | tokenChanged=true |
|
||||
| PASS | refresh sets a rotated refresh cookie | rotated cookie present |
|
||||
| PASS | refreshed bearer token can access protected dashboard summary | status=200, duration=387ms |
|
||||
| PASS | logout revokes current refresh session | status=204, duration=386ms |
|
||||
| PASS | refresh after logout is rejected | status=401, duration=374ms |
|
||||
| PASS | low-privilege captcha answer can be parsed from SVG | length=5 |
|
||||
| PASS | low-privilege user can login | status=200, duration=1152ms |
|
||||
| PASS | low-privilege login returns dashboard.view only | {"id":"usr_102e3dcda767449f9f288ec09e8b","username":"codex.low","displayName":"Codex低权限测试用户","roles":["自动化低权限角色"],"permissionCount":1} |
|
||||
| PASS | low-privilege user can access allowed dashboard summary | status=200, duration=538ms |
|
||||
| PASS | low-privilege user is forbidden from users.manage endpoint | status=403, duration=449ms |
|
||||
| PASS | admin account has non-empty permission set | permissionCount=24, roles=超级管理员 |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted.
|
||||
- This run uses the remote B service as a black-box API target.
|
||||
- The low-privilege role and user are created or updated through the admin API before RBAC assertions.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Remote SIP Calls, CDR, and Billing API Test Report
|
||||
|
||||
Date: 2026-06-29T05:34:25.003Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | admin can login | status=200, duration=1308ms |
|
||||
| PASS | admin login returns access token | tokenLength=296 |
|
||||
| PASS | low-privilege user can login for RBAC checks | status=200, duration=1060ms |
|
||||
| PASS | low-privilege user cannot list CDRs | status=403, duration=477ms |
|
||||
| PASS | low-privilege user cannot list active calls | status=403, duration=464ms |
|
||||
| PASS | CDR list can be queried | status=200, duration=1818ms |
|
||||
| PASS | CDR list returns page shape | total=56, take=20, skip=0, hasMore=true |
|
||||
| PASS | CDR list items do not expose secrets | items=20 |
|
||||
| PASS | CDR detail can be fetched | status=200, duration=683ms |
|
||||
| PASS | CDR detail matches list item id and event id | id=raw_4281ea422d1c4465964c6bf054a90115, eventId=s28-ok-1782701051-2331-s40-01-1782701049649-q3u-fde892c670e534f8 |
|
||||
| PASS | CDR detail does not expose secrets | id=raw_4281ea422d1c4465964c6bf054a90115 |
|
||||
| PASS | rated CDR detail has numeric fee fields | billSec=6, customerFee=0.012000, vendorCost=0.012000, grossProfit=0.000000 |
|
||||
| PASS | CDR caller filter can be queried | status=200, duration=2032ms |
|
||||
| PASS | CDR caller filter returns matching rows | rows=9, caller=s36-1001 |
|
||||
| PASS | CDR carrier filter can be queried | status=200, duration=1585ms |
|
||||
| PASS | CDR carrier filter returns matching rows | rows=10, carrier=UNKNOWN |
|
||||
| PASS | invalid CDR carrier is rejected | status=400, duration=774ms |
|
||||
| PASS | invalid carrier returns CARRIER_INVALID | code=CARRIER_INVALID |
|
||||
| PASS | invalid CDR pagination is rejected | status=400, duration=464ms |
|
||||
| PASS | invalid pagination returns QUERY_INVALID | code=QUERY_INVALID |
|
||||
| PASS | invalid CDR time range is rejected | status=400, duration=458ms |
|
||||
| PASS | invalid time range returns TIME_RANGE_INVALID | code=TIME_RANGE_INVALID |
|
||||
| PASS | missing CDR detail returns 404 | status=404, duration=389ms |
|
||||
| PASS | missing CDR returns CDR_NOT_FOUND | code=CDR_NOT_FOUND |
|
||||
| PASS | active calls list can be queried | status=200, duration=969ms |
|
||||
| PASS | active calls response has normalized shape | source=opensips-mi, total=0 |
|
||||
| PASS | invalid active call hangup id is rejected before MI call | status=400, duration=561ms |
|
||||
| PASS | invalid active call id returns ACTIVE_CALL_ID_INVALID | code=ACTIVE_CALL_ID_INVALID |
|
||||
|
||||
## Not Executed By This Black-Box API Run
|
||||
|
||||
- Real IP/SIP customer calls from T through A to UAS.
|
||||
- SIP Digest wrong-password REGISTER/INVITE signaling assertions.
|
||||
- Low-balance hot-path rejection assertions.
|
||||
- Primary/backup route failover proven by live call CDR vendorGatewayId.
|
||||
- Redis Stream CDR injection, duplicate event idempotency, deadletter, and retry/pending checks.
|
||||
- Direct customer balance deduction by CDR Worker transaction.
|
||||
|
||||
These require A/B/T SIP tooling or Redis/DB side access in addition to the HTTPS API.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Remote Customers, Recharge, and Balance Test Report
|
||||
|
||||
Date: 2026-06-29T05:18:50.822Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
Customer Name: 自动化8.2客户
|
||||
Customer Domain: codex-82.example.test
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | admin can login | status=200, duration=544ms |
|
||||
| PASS | admin login returns access token | tokenLength=296 |
|
||||
| PASS | low-privilege user can login for RBAC checks | status=200, duration=454ms |
|
||||
| PASS | low-privilege user cannot list customers | status=403, duration=395ms |
|
||||
| PASS | test customer is created | status=201, duration=1007ms |
|
||||
| PASS | test customer has expected credit/min balance | creditLimit=100.000000, minBalance=5.000000 |
|
||||
| PASS | customer detail can be fetched | status=200, duration=528ms |
|
||||
| PASS | available balance equals balance plus credit limit | balance=0.000000, creditLimit=100.000000, available=100.000000 |
|
||||
| PASS | customer can be disabled | status=201, duration=401ms |
|
||||
| PASS | disabled customer status is DISABLED | status=DISABLED |
|
||||
| PASS | customer can be enabled | status=201, duration=403ms |
|
||||
| PASS | enabled customer status is ENABLED | status=ENABLED |
|
||||
| PASS | positive customer recharge succeeds | status=201, duration=410ms |
|
||||
| PASS | positive recharge balance delta is +10.000000 | before=0.000000, after=10.000000 |
|
||||
| PASS | same idempotency key with same body returns cached success | status=201, duration=412ms |
|
||||
| PASS | idempotent duplicate returns same recharge id | first=rch_3dd6d1209d2f4d12ad69926097d7f2aa, duplicate=rch_3dd6d1209d2f4d12ad69926097d7f2aa |
|
||||
| PASS | same idempotency key with different body is rejected | status=409, duration=404ms |
|
||||
| FAIL | negative customer recharge deducts balance | status=400, duration=866ms |
|
||||
| FAIL | negative recharge balance delta is -3.000000 | before=undefined, after=undefined, code=MONEY_INVALID |
|
||||
| PASS | customer recharge list can be filtered by account | status=200, duration=1857ms |
|
||||
| PASS | recharge list contains positive recharge record | total=1 |
|
||||
| PASS | low-privilege user cannot recharge customer | status=403, duration=618ms |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted.
|
||||
- Negative recharge is asserted as a required business rule: negative amount should deduct customer balance.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Remote Customer Gateways, Business Prefixes, and Config Intent Test Report
|
||||
|
||||
Date: 2026-06-29T05:22:45.686Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
Business Prefix: C83
|
||||
Customer Name: 自动化8.3客户
|
||||
Gateway Name: 自动化8.3客户网关
|
||||
Gateway IP: 100.83.0.10
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | admin can login | status=200, duration=902ms |
|
||||
| PASS | admin login returns access token | tokenLength=296 |
|
||||
| PASS | low-privilege user can login for RBAC checks | status=200, duration=830ms |
|
||||
| PASS | low-privilege user cannot list business prefixes | status=403, duration=614ms |
|
||||
| PASS | low-privilege user cannot list customer gateways | status=403, duration=417ms |
|
||||
| PASS | invalid business prefix is rejected | status=400, duration=421ms |
|
||||
| PASS | invalid business prefix returns BUSINESS_PREFIX_INVALID | code=BUSINESS_PREFIX_INVALID |
|
||||
| PASS | business prefix is created | status=201, duration=424ms |
|
||||
| PASS | business prefix has expected values | id=bp_b9988f12a1bb418c9e64ce0754d32, prefix=C83, priority=83 |
|
||||
| PASS | business prefix can be disabled | status=201, duration=432ms |
|
||||
| PASS | disabled business prefix status is DISABLED | status=DISABLED |
|
||||
| PASS | business prefix can be enabled | status=201, duration=427ms |
|
||||
| PASS | enabled business prefix status is ENABLED | status=ENABLED |
|
||||
| PASS | test customer is created | status=201, duration=482ms |
|
||||
| PASS | landing line group list can be fetched | status=200, duration=1279ms |
|
||||
| PASS | at least one landing line group is available for gateway binding | lineGroupId=llg_4e6997487b774379836631aee19c, name=S36 Flow 20260623160046 Line Group |
|
||||
| PASS | invalid customer gateway source IP is rejected | status=400, duration=477ms |
|
||||
| PASS | invalid source IP returns SOURCE_IP_INVALID | code=SOURCE_IP_INVALID |
|
||||
| PASS | SIP gateway without password is rejected | status=400, duration=444ms |
|
||||
| FAIL | missing SIP password returns SIP_PASSWORD_REQUIRED | code=VALIDATION_ERROR |
|
||||
| PASS | customer gateway is created | status=201, duration=1048ms |
|
||||
| PASS | customer gateway binds IP, caller prefix, and business prefix | gatewayId=cgw_16f4a342caf74ab5b3e34457113c, sourceIps=100.83.0.10, callerPrefixes=055183 |
|
||||
| PASS | duplicate source IP and business prefix gateway is rejected | status=409, duration=786ms |
|
||||
| PASS | duplicate gateway returns match conflict code | code=CUSTOMER_GATEWAY_MATCH_CONFLICT |
|
||||
| PASS | customer gateway can be disabled | status=201, duration=587ms |
|
||||
| PASS | disabled customer gateway status is DISABLED | status=DISABLED |
|
||||
| PASS | customer gateway can be enabled | status=201, duration=440ms |
|
||||
| PASS | enabled customer gateway status is ENABLED | status=ENABLED |
|
||||
| PASS | business prefix in use cannot be deleted | status=400, duration=390ms |
|
||||
| PASS | business prefix in use returns BUSINESS_PREFIX_IN_USE | code=BUSINESS_PREFIX_IN_USE |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted.
|
||||
- Business prefix and customer gateway mutations enqueue config outbox events server-side.
|
||||
- Config publication manifest is not exposed by the black-box API; DB or Redis observation is required to assert worker publication directly.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Remote Customer Gateways, Business Prefixes, and Config Intent Test Report
|
||||
|
||||
Date: 2026-06-29T05:23:46.288Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
Business Prefix: C83
|
||||
Customer Name: 自动化8.3客户
|
||||
Gateway Name: 自动化8.3客户网关
|
||||
Gateway IP: 100.83.0.10
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | admin can login | status=200, duration=597ms |
|
||||
| PASS | admin login returns access token | tokenLength=296 |
|
||||
| PASS | low-privilege user can login for RBAC checks | status=200, duration=452ms |
|
||||
| PASS | low-privilege user cannot list business prefixes | status=403, duration=389ms |
|
||||
| PASS | low-privilege user cannot list customer gateways | status=403, duration=833ms |
|
||||
| PASS | invalid business prefix is rejected | status=400, duration=380ms |
|
||||
| PASS | invalid business prefix returns BUSINESS_PREFIX_INVALID | code=BUSINESS_PREFIX_INVALID |
|
||||
| PASS | business prefix is updated | status=200, duration=429ms |
|
||||
| PASS | business prefix has expected values | id=bp_b9988f12a1bb418c9e64ce0754d32, prefix=C83, priority=83 |
|
||||
| PASS | business prefix can be disabled | status=201, duration=394ms |
|
||||
| PASS | disabled business prefix status is DISABLED | status=DISABLED |
|
||||
| PASS | business prefix can be enabled | status=201, duration=387ms |
|
||||
| PASS | enabled business prefix status is ENABLED | status=ENABLED |
|
||||
| PASS | test customer is updated | status=200, duration=430ms |
|
||||
| PASS | landing line group list can be fetched | status=200, duration=578ms |
|
||||
| PASS | at least one landing line group is available for gateway binding | lineGroupId=llg_4e6997487b774379836631aee19c, name=S36 Flow 20260623160046 Line Group |
|
||||
| PASS | invalid customer gateway source IP is rejected | status=400, duration=795ms |
|
||||
| PASS | invalid source IP returns SOURCE_IP_INVALID | code=SOURCE_IP_INVALID |
|
||||
| PASS | SIP gateway without password is rejected | status=400, duration=382ms |
|
||||
| PASS | missing SIP password returns a validation error | code=VALIDATION_ERROR |
|
||||
| PASS | customer gateway is updated | status=200, duration=452ms |
|
||||
| PASS | customer gateway binds IP, caller prefix, and business prefix | gatewayId=cgw_16f4a342caf74ab5b3e34457113c, sourceIps=100.83.0.10, callerPrefixes=055183 |
|
||||
| PASS | duplicate source IP and business prefix gateway is rejected | status=409, duration=585ms |
|
||||
| PASS | duplicate gateway returns match conflict code | code=CUSTOMER_GATEWAY_MATCH_CONFLICT |
|
||||
| PASS | customer gateway can be disabled | status=201, duration=469ms |
|
||||
| PASS | disabled customer gateway status is DISABLED | status=DISABLED |
|
||||
| PASS | customer gateway can be enabled | status=201, duration=598ms |
|
||||
| PASS | enabled customer gateway status is ENABLED | status=ENABLED |
|
||||
| PASS | business prefix in use cannot be deleted | status=400, duration=385ms |
|
||||
| PASS | business prefix in use returns BUSINESS_PREFIX_IN_USE | code=BUSINESS_PREFIX_IN_USE |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted.
|
||||
- Business prefix and customer gateway mutations enqueue config outbox events server-side.
|
||||
- Config publication manifest is not exposed by the black-box API; DB or Redis observation is required to assert worker publication directly.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Remote Dashboard, Active Calls, and Audit Test Report
|
||||
|
||||
Date: 2026-06-29T05:51:04.581Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | admin can login | status=200, duration=1046ms |
|
||||
| PASS | admin login returns access token | tokenLength=296 |
|
||||
| PASS | low-privilege user can login for RBAC checks | status=200, duration=675ms |
|
||||
| PASS | dashboard summary can be queried | status=200, duration=539ms |
|
||||
| PASS | dashboard summary shape and Shanghai day window are valid | {"window":{"start":"2026-06-28T16:00:00.000Z","end":"2026-06-29T05:50:47.137Z","timezone":"Asia/Shanghai"},"calls":{"totalCalls":1,"answeredCalls":1,"failedCalls":0,"answerRate":"1.0000","totalDurationSec":6},"money":{"customerFee":"0.012000","vendorCost":"0.012000","grossProfit":"0.000000"},"quality":{"pendingReviews":54}} |
|
||||
| PASS | dashboard trends can be queried with fixed range | status=200, duration=408ms |
|
||||
| PASS | dashboard trends return fixed contiguous buckets | bucketCount=2 |
|
||||
| PASS | invalid dashboard trend bucket is rejected | status=400, duration=392ms |
|
||||
| PASS | invalid trend bucket returns DASHBOARD_BUCKET_INVALID | code=DASHBOARD_BUCKET_INVALID |
|
||||
| PASS | too-large dashboard trend range is rejected | status=400, duration=379ms |
|
||||
| PASS | too-large trend range returns INTEGER_INVALID | code=INTEGER_INVALID |
|
||||
| PASS | low dashboard-only user can query dashboard summary | status=200, duration=975ms |
|
||||
| PASS | active calls can be listed | status=200, duration=840ms |
|
||||
| PASS | active calls response shape is stable | {"total":0,"source":"opensips-mi"} |
|
||||
| PASS | low dashboard-only user cannot list active calls | status=403, duration=379ms |
|
||||
| PASS | invalid active call id is rejected (../x) | status=400, duration=410ms |
|
||||
| PASS | invalid active call id returns ACTIVE_CALL_ID_INVALID (../x) | code=ACTIVE_CALL_ID_INVALID |
|
||||
| PASS | invalid active call id is rejected (;rm -rf) | status=400, duration=388ms |
|
||||
| PASS | invalid active call id returns ACTIVE_CALL_ID_INVALID (;rm -rf) | code=ACTIVE_CALL_ID_INVALID |
|
||||
| PASS | invalid active call id is rejected (contains space) | status=400, duration=384ms |
|
||||
| PASS | invalid active call id returns ACTIVE_CALL_ID_INVALID (contains space) | code=ACTIVE_CALL_ID_INVALID |
|
||||
| PASS | invalid active call id is rejected (line\nbreak) | status=400, duration=385ms |
|
||||
| PASS | invalid active call id returns ACTIVE_CALL_ID_INVALID (line\nbreak) | code=ACTIVE_CALL_ID_INVALID |
|
||||
| FAIL | invalid active call id is rejected (xxxxxxxxxxxxxxxxxxxx) | status=404, duration=377ms |
|
||||
| FAIL | invalid active call id returns ACTIVE_CALL_ID_INVALID (xxxxxxxxxxxxxxxxxxxx) | code=undefined |
|
||||
| PASS | low dashboard-only user cannot hang up calls | status=403, duration=380ms |
|
||||
| PASS | audit logs can be listed | status=200, duration=756ms |
|
||||
| PASS | audit list shape is valid | count=10, total=113 |
|
||||
| PASS | low dashboard-only user cannot list audit logs | status=403, duration=404ms |
|
||||
| PASS | invalid audit result filter is rejected | status=400, duration=380ms |
|
||||
| PASS | invalid audit result returns AUDIT_RESULT_INVALID | code=AUDIT_RESULT_INVALID |
|
||||
| PASS | audit logs can be filtered by result | status=200, duration=899ms |
|
||||
| PASS | audit success filter only returns SUCCESS rows | count=5 |
|
||||
| PASS | roles can be listed for temporary audit user setup | status=200, duration=758ms |
|
||||
| PASS | dashboard-capable role is available | roleId=ROLE_TECH_OPS |
|
||||
| PASS | temporary user with sensitive password can be created | status=201, expected=201, duration=776ms |
|
||||
| PASS | created temporary user response does not expose password fields | {"id":"usr_ddd21fd564f6456a8c120dc940d4","username":"codex.audit.1782712243816"} |
|
||||
| PASS | temporary user password reset succeeds | status=201, duration=580ms |
|
||||
| PASS | password reset response does not expose sensitive fields | {"id":"usr_ddd21fd564f6456a8c120dc940d4","username":"codex.audit.1782712243816"} |
|
||||
| PASS | password reset audit can be filtered by module/action/object/result | status=200, duration=437ms |
|
||||
| PASS | password reset audit row exists | auditId=aud_09853278ea1a4d7b8ff64275a926f9ac |
|
||||
| PASS | password reset audit detail can be fetched | status=200, duration=1000ms |
|
||||
| FAIL | password reset audit detail redacts sensitive body fields | {"id":"aud_09853278ea1a4d7b8ff64275a926f9ac","redactedPassword":"[REDACTED]"} |
|
||||
| PASS | temporary audit user cleanup is stable | status=200, expected=200/404, duration=1695ms |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted from console and report details.
|
||||
- DASH-001 aggregate accuracy and DASH-002 exact Shanghai day-boundary attribution still require SQL comparison against seeded boundary CDRs.
|
||||
- ACT-001/ACT-002 real long-call normalization and successful hangup require an active OpenSIPS dialog on A; this black-box run verifies list contract, RBAC, and invalid dialog-id safety.
|
||||
- AUD-002 application log full-text checks require host-side log access; this run verifies API response and audit detail redaction.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Remote Dashboard, Active Calls, and Audit Test Report
|
||||
|
||||
Date: 2026-06-29T05:52:07.874Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | admin can login | status=200, duration=457ms |
|
||||
| PASS | admin login returns access token | tokenLength=296 |
|
||||
| PASS | low-privilege user can login for RBAC checks | status=200, duration=1291ms |
|
||||
| PASS | dashboard summary can be queried | status=200, duration=433ms |
|
||||
| PASS | dashboard summary shape and Shanghai day window are valid | {"window":{"start":"2026-06-28T16:00:00.000Z","end":"2026-06-29T05:51:50.712Z","timezone":"Asia/Shanghai"},"calls":{"totalCalls":1,"answeredCalls":1,"failedCalls":0,"answerRate":"1.0000","totalDurationSec":6},"money":{"customerFee":"0.012000","vendorCost":"0.012000","grossProfit":"0.000000"},"quality":{"pendingReviews":54}} |
|
||||
| PASS | dashboard trends can be queried with fixed range | status=200, duration=382ms |
|
||||
| PASS | dashboard trends return fixed contiguous buckets | bucketCount=2 |
|
||||
| PASS | invalid dashboard trend bucket is rejected | status=400, duration=800ms |
|
||||
| PASS | invalid trend bucket returns DASHBOARD_BUCKET_INVALID | code=DASHBOARD_BUCKET_INVALID |
|
||||
| PASS | too-large dashboard trend range is rejected | status=400, duration=1413ms |
|
||||
| PASS | too-large trend range returns INTEGER_INVALID | code=INTEGER_INVALID |
|
||||
| PASS | low dashboard-only user can query dashboard summary | status=200, duration=806ms |
|
||||
| PASS | active calls can be listed | status=200, duration=807ms |
|
||||
| PASS | active calls response shape is stable | {"total":0,"source":"opensips-mi"} |
|
||||
| PASS | low dashboard-only user cannot list active calls | status=403, duration=379ms |
|
||||
| PASS | invalid active call id is rejected (../x) | status=400, duration=382ms |
|
||||
| PASS | invalid active call id returns ACTIVE_CALL_ID_INVALID (../x) | code=ACTIVE_CALL_ID_INVALID |
|
||||
| PASS | invalid active call id is rejected (;rm -rf) | status=400, duration=867ms |
|
||||
| PASS | invalid active call id returns ACTIVE_CALL_ID_INVALID (;rm -rf) | code=ACTIVE_CALL_ID_INVALID |
|
||||
| PASS | invalid active call id is rejected (contains space) | status=400, duration=385ms |
|
||||
| PASS | invalid active call id returns ACTIVE_CALL_ID_INVALID (contains space) | code=ACTIVE_CALL_ID_INVALID |
|
||||
| PASS | invalid active call id is rejected (line\nbreak) | status=400, duration=386ms |
|
||||
| PASS | invalid active call id returns ACTIVE_CALL_ID_INVALID (line\nbreak) | code=ACTIVE_CALL_ID_INVALID |
|
||||
| FAIL | invalid active call id is rejected (xxxxxxxxxxxxxxxxxxxx) | status=404, duration=437ms |
|
||||
| FAIL | invalid active call id returns ACTIVE_CALL_ID_INVALID (xxxxxxxxxxxxxxxxxxxx) | code=undefined |
|
||||
| PASS | low dashboard-only user cannot hang up calls | status=403, duration=414ms |
|
||||
| PASS | audit logs can be listed | status=200, duration=1314ms |
|
||||
| PASS | audit list shape is valid | count=10, total=120 |
|
||||
| PASS | low dashboard-only user cannot list audit logs | status=403, duration=463ms |
|
||||
| PASS | invalid audit result filter is rejected | status=400, duration=377ms |
|
||||
| PASS | invalid audit result returns AUDIT_RESULT_INVALID | code=AUDIT_RESULT_INVALID |
|
||||
| PASS | audit logs can be filtered by result | status=200, duration=558ms |
|
||||
| PASS | audit success filter only returns SUCCESS rows | count=5 |
|
||||
| PASS | roles can be listed for temporary audit user setup | status=200, duration=424ms |
|
||||
| PASS | dashboard-capable role is available | roleId=ROLE_TECH_OPS |
|
||||
| PASS | temporary user with sensitive password can be created | status=201, expected=201, duration=432ms |
|
||||
| PASS | created temporary user response does not expose password fields | {"id":"usr_b548190698424ba9b7b4a6c37bb2","username":"codex.audit.1782712309898"} |
|
||||
| PASS | temporary user password reset succeeds | status=201, duration=432ms |
|
||||
| PASS | password reset response does not expose sensitive fields | {"id":"usr_b548190698424ba9b7b4a6c37bb2","username":"codex.audit.1782712309898"} |
|
||||
| PASS | password reset audit can be filtered by module/action/object/result | status=200, duration=695ms |
|
||||
| PASS | password reset audit row exists | auditId=aud_a5b773a3ee0c4397a81eaf2b8fbac455 |
|
||||
| PASS | password reset audit detail can be fetched | status=200, duration=580ms |
|
||||
| PASS | password reset audit detail redacts sensitive body fields | {"id":"aud_a5b773a3ee0c4397a81eaf2b8fbac455","redactedPassword":"[REDACTED]"} |
|
||||
| PASS | temporary audit user cleanup is stable | status=200, expected=200/404, duration=475ms |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted from console and report details.
|
||||
- DASH-001 aggregate accuracy and DASH-002 exact Shanghai day-boundary attribution still require SQL comparison against seeded boundary CDRs.
|
||||
- ACT-001/ACT-002 real long-call normalization and successful hangup require an active OpenSIPS dialog on A; this black-box run verifies list contract, RBAC, and invalid dialog-id safety.
|
||||
- AUD-002 application log full-text checks require host-side log access; this run verifies API response and audit detail redaction.
|
||||
@@ -0,0 +1,51 @@
|
||||
# 8.10 运维发布、备份与回滚远程测试报告
|
||||
|
||||
- Target: `https://100.90.90.91/`
|
||||
- SSH target: `lisglosips-b`, `lisglosips-a`, `lisglosips-t`
|
||||
- Started at: `2026-06-29T06:30:00Z`
|
||||
- Completed at: `2026-06-29T06:42:36Z`
|
||||
- Scope: 8.10 发布工件、发布前检查、备份、恢复、灰度呼叫、回滚与迁移复核
|
||||
|
||||
## Summary
|
||||
|
||||
| Result | Count |
|
||||
| --- | ---: |
|
||||
| PASS | 5 |
|
||||
| PARTIAL | 1 |
|
||||
| BLOCKED | 6 |
|
||||
| N/A | 1 |
|
||||
|
||||
## Findings
|
||||
|
||||
| Case | Result | Evidence |
|
||||
| --- | --- | --- |
|
||||
| OPS-000 发布工件完整性检查 | PASS | `pnpm release:artifact -- --release-id codex-ops-check-20260629063000 --check --allow-non-linux` 通过;输出确认 39 个必需条目齐全。 |
|
||||
| OPS-001 B 发布前检查 | PARTIAL | `/opt/lisglosips/current` 指向 `/opt/lisglosips/releases/s45-vendor-cps-sipstate-20260629113500`;B 上 `mysql`、`redis-server`、`nginx`、`lisglosips@api`、`lisglosips@cdr-worker`、`lisglosips@recording-worker`、`lisglosips@config-publisher`、`heplify-server`、`grafana-server`、`lisglosips-prometheus.service` 均为 active;`/api/v2/health/ready` 返回 database/redis ok;但非 sudo 用户无法读取或执行 `/opt/lisglosips/current/infra/server-b/s30/lisglosips-release-preflight.sh`,脚本级 preflight 被权限阻塞。 |
|
||||
| OPS-002 MySQL 备份 | BLOCKED | 非 sudo 用户访问 `/data/backups/mysql` 返回 `权限不够`;无法触发 `lisglosips-backup.service` 或校验最新备份文件。 |
|
||||
| OPS-003 Redis 备份 | BLOCKED | 非 sudo 用户访问 `/data/backups/redis` 返回 `权限不够`;无法触发备份或校验最新 RDB/元数据。 |
|
||||
| OPS-004 隔离恢复演练 | BLOCKED | 需要可读备份文件、临时恢复目录/容器或 root 级恢复权限;本轮未获得 sudo,未执行恢复演练。 |
|
||||
| OPS-005 灰度呼叫验收 | PASS | 从 T 发起呼叫成功:Call-ID `s28-1782715222404-1w73ad89@lisglosips-t`,INVITE 收到 `SIP/2.0 200 OK`,BYE 收到 `SIP/2.0 200 OK`。API 反查 CDR 成功,`sampleId=raw_95fb2de5aafb4b0a808ddccc6293d7da`;录音列表找到对应记录,`sampleId=rec_47012fa5341e42f19fec400c1972b6ae`,状态 `READY`。 |
|
||||
| OPS-006 回滚脚本语法检查 | BLOCKED | 本机无 `bash`;B 上 `/opt/lisglosips/current/infra/server-b/s30/lisglosips-release-preflight.sh` 与 `lisglosips-release-rollback.sh` 对当前用户不可读;未能执行 `bash -n`。 |
|
||||
| OPS-007 应用回滚演练 | BLOCKED | 需要修改 `/opt/lisglosips/current` 指针并重启服务,属于 root/维护窗口动作;当前 sudo 不可用,未执行真实回滚。 |
|
||||
| OPS-008 OpenSIPS 配置恢复演练 | BLOCKED | A 上以非 root 执行 `opensips -C -f /etc/opensips/opensips.cfg` 因读取配置权限不足失败;配置恢复脚本路径/权限未满足,未执行恢复演练。 |
|
||||
| OPS-009 阿里云迁移复核 | N/A | 本轮目标为现有测试机 `100.90.90.91`,不是阿里云迁移后的新环境;仅做当前环境可用性复核。 |
|
||||
| 发布后 HTTP/API 健康回归 | PASS | `GET /` 返回 200;`/api/v2/health/ready` 返回 `{"config":"ok","database":"ok","redis":"ok"}`。 |
|
||||
| 远程 smoke 回归 | PASS | `pnpm test:remote-smoke` 全部通过,报告:`tests/reports/REMOTE_SMOKE_20260629T064035Z.md`。 |
|
||||
|
||||
## Blocking Notes
|
||||
|
||||
- B 上当前 SSH 用户无法免密 sudo,`sudo -n true` 返回需要密码。
|
||||
- `/data/backups/mysql`、`/data/backups/redis`、发布 preflight/rollback 脚本均对当前用户不可读。
|
||||
- 因此备份触发、备份文件校验、隔离恢复、真实应用回滚、OpenSIPS 配置恢复只能在具备 root 权限或维护窗口时继续。
|
||||
|
||||
## Commands Run
|
||||
|
||||
```powershell
|
||||
corepack pnpm@10.33.0 release:artifact -- --release-id codex-ops-check-20260629063000 --check --allow-non-linux
|
||||
ssh -F .codex-private\ssh\config lisglosips-b "readlink -f /opt/lisglosips/current"
|
||||
ssh -F .codex-private\ssh\config lisglosips-b "systemctl is-active mysql redis-server nginx lisglosips@api lisglosips@cdr-worker lisglosips@recording-worker lisglosips@config-publisher heplify-server grafana-server lisglosips-prometheus.service"
|
||||
ssh -F .codex-private\ssh\config lisglosips-b "find /data/backups/mysql -mindepth 1 -maxdepth 1 -type d"
|
||||
ssh -F .codex-private\ssh\config lisglosips-b "find /data/backups/redis -mindepth 1 -maxdepth 1 -type d"
|
||||
ssh -F .codex-private\ssh\config lisglosips-t "python3 /opt/lisglosips-s28/lisglosips-s28-sip.py invite --hold 3 --timeout 6 --media-port 31500"
|
||||
corepack pnpm@10.33.0 test:remote-smoke
|
||||
```
|
||||
@@ -0,0 +1,43 @@
|
||||
# Remote Performance, Fault, and Security Test Report
|
||||
|
||||
Date: 2026-06-29T06:16:21.982Z
|
||||
Base URL: https://100.90.90.91
|
||||
Concurrency: 12 ready + 12 captcha requests
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | HTTPS root is reachable before light concurrency | status=200, duration=2087ms |
|
||||
| PASS | HTTPS root contains app root | contentType=text/html, bytes=434 |
|
||||
| PASS | ready health is ok before light concurrency | status=200, duration=389ms |
|
||||
| PASS | ready health reports database and redis ok before light concurrency | body={"status":"ok","service":"api","timestamp":"2026-06-29T06:15:52.352Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | admin can login | status=200, duration=1103ms |
|
||||
| PASS | admin login returns access token | tokenLength=296 |
|
||||
| PASS | low-privilege user can login for RBAC checks | status=200, duration=773ms |
|
||||
| PASS | PERF light API burst returns only 200 responses | requests=24, failed=0, wallMs=15477 |
|
||||
| FAIL | PERF light API burst p95 stays under 10s | p95=14919ms, max=15441ms |
|
||||
| PASS | ready health recovers after light concurrency | status=200, duration=604ms |
|
||||
| PASS | ready health reports database and redis ok after light concurrency | body={"status":"ok","service":"api","timestamp":"2026-06-29T06:16:11.657Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | SEC forged bearer token is rejected | status=401, duration=372ms |
|
||||
| PASS | SEC forged token error does not leak internals | body={"code":"AUTH_REQUIRED","message":"Authentication is required."} |
|
||||
| PASS | SEC unauthenticated write is rejected | status=401, duration=775ms |
|
||||
| PASS | SEC unauthenticated write error does not leak internals | body={"code":"AUTH_REQUIRED","message":"Authentication is required."} |
|
||||
| PASS | SEC low-privilege user cannot create customer | status=403, duration=605ms |
|
||||
| PASS | SEC low-privilege write error does not leak internals | body={"code":"RBAC_FORBIDDEN","message":"Permission denied."} |
|
||||
| PASS | SEC replay test customer is created | status=201, duration=1141ms |
|
||||
| PASS | SEC first idempotent recharge succeeds | status=201, duration=535ms |
|
||||
| PASS | SEC exact idempotent replay returns success | status=201, duration=456ms |
|
||||
| PASS | SEC exact idempotent replay returns same recharge id | first=rch_44943fc6e1d3483ab17eee61fe279b1d, replay=rch_44943fc6e1d3483ab17eee61fe279b1d |
|
||||
| PASS | SEC conflicting idempotency replay is rejected | status=409, duration=601ms |
|
||||
| PASS | SEC conflicting replay error does not leak original body | body={"code":"IDEMPOTENCY_KEY_CONFLICT","message":"Idempotency key was used by another request."} |
|
||||
| PASS | SEC low-privilege user cannot replay/write recharge | status=403, duration=371ms |
|
||||
| PASS | SEC missing recording playback returns 404 | status=404, duration=575ms |
|
||||
| PASS | SEC missing recording playback error does not expose paths | body={"code":"RECORDING_NOT_READY","message":"Recording is not available for playback."} |
|
||||
| PASS | SEC encoded traversal recording id is rejected safely | status=404, body={"code":"RECORDING_NOT_READY","message":"Recording is not available for playback."} |
|
||||
| PASS | SEC traversal playback error does not expose filesystem paths | body={"code":"RECORDING_NOT_READY","message":"Recording is not available for playback."} |
|
||||
|
||||
## Notes
|
||||
|
||||
- This run intentionally avoids disruptive fault injection: no Worker, MySQL, Redis, OpenSIPS, or SIP traffic was stopped or modified.
|
||||
- PERF-001/PERF-002 SIP call concurrency, SEC-001 illegal-source SIP probe, and SEC-002 CPS probe still require A/T-side SIP tooling and CDR/recording verification.
|
||||
- FAIL-001 through FAIL-004 require an explicit maintenance window, rollback point, and service-stop approval before execution.
|
||||
- The executed subset covers HTTPS/API light concurrency, service recovery after burst, forged/unauthenticated/low-privilege access, idempotency replay, and recording path-safety black-box checks.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Remote Performance, Fault, and Security Disruptive Test Report
|
||||
|
||||
Date: 2026-06-29T06:29:20Z
|
||||
Base URL: https://100.90.90.91
|
||||
Scope: 8.9 disruptive / SIP-side follow-up after `REMOTE_PERFORMANCE_SECURITY_20260629T061621Z.md`
|
||||
|
||||
## Baseline
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | B services active before/after run | `lisglosips@api`, `lisglosips@cdr-worker`, `lisglosips@recording-worker`, `mysql`, `redis-server` all active |
|
||||
| PASS | A services active before run | `opensips`, `rtpengine-daemon`, `rtpengine-recording-daemon`, `lisglosips-redis-auth-proxy` all active |
|
||||
| PASS | T services active before run | `lisglosips-s28-uas`, `opensips` active |
|
||||
| PASS | Final HTTPS smoke | `/`, `/api/v2/health/live`, `/api/v2/health/ready`, `/api/v2/auth/captcha` all PASS; latest smoke report `REMOTE_SMOKE_20260629T062920Z.md` |
|
||||
|
||||
## SIP Concurrency
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | PERF-001 5 concurrent calls | 5/5 received `100 Giving it a try`, `200 OK`, and BYE `200 OK` |
|
||||
| PASS | PERF-001 CDR verification | 5/5 call IDs found in `/api/v2/cdrs?take=100` |
|
||||
| PASS | PERF-001 recording verification | 5/5 call IDs found in `/api/v2/recordings?limit=100` |
|
||||
| PASS | PERF-002 12 short-burst calls | 12/12 received `100 Giving it a try`, `200 OK`, and BYE `200 OK` |
|
||||
| PASS | PERF-002 CDR verification | 12/12 call IDs found in `/api/v2/cdrs?take=100` |
|
||||
| PASS | PERF-002 recording verification | 12/12 call IDs found in `/api/v2/recordings?limit=100` after worker catch-up wait |
|
||||
|
||||
5-call IDs:
|
||||
|
||||
- `s28-1782714314674-tprj1vk2@lisglosips-t`
|
||||
- `s28-1782714314655-ye44k7c7@lisglosips-t`
|
||||
- `s28-1782714314670-zqsgouuh@lisglosips-t`
|
||||
- `s28-1782714314677-vkrthfau@lisglosips-t`
|
||||
- `s28-1782714314679-j47gb9tl@lisglosips-t`
|
||||
|
||||
12-call IDs:
|
||||
|
||||
- `s28-1782714339590-pi088vy9@lisglosips-t`
|
||||
- `s28-1782714339585-t0wbt40b@lisglosips-t`
|
||||
- `s28-1782714339580-ooqd773x@lisglosips-t`
|
||||
- `s28-1782714339585-b38gwxb1@lisglosips-t`
|
||||
- `s28-1782714339585-wn61wl1x@lisglosips-t`
|
||||
- `s28-1782714339573-w6xxwzmp@lisglosips-t`
|
||||
- `s28-1782714339589-lxrh6ht3@lisglosips-t`
|
||||
- `s28-1782714339581-usu8mnjx@lisglosips-t`
|
||||
- `s28-1782714339590-51r89nel@lisglosips-t`
|
||||
- `s28-1782714339589-63h8mpr7@lisglosips-t`
|
||||
- `s28-1782714339584-kmbwlurm@lisglosips-t`
|
||||
- `s28-1782714339575-kv082r5b@lisglosips-t`
|
||||
|
||||
## Security Probes
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | SEC-001 illegal-source SIP probe | From B to A `100.90.90.90:15060`, Call-ID `codex89-illegal-1782714470-8090@lisglosips-b`, no response within 3s |
|
||||
| WARN | SEC-002 20-call CPS burst | 20/20 INVITE received `200 OK`, but 20/20 BYE returned `403 Rate Limited` |
|
||||
| PASS | SEC-002 recovery after burst | One normal call after 5s recovered and received BYE `200 OK`; Call-ID `s28-1782714527323-zdscgrrx@lisglosips-t` |
|
||||
|
||||
## Fault Injection
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| BLOCKED | FAIL-001 Recording Worker stop/recover | B `sudo -n true` returns `sudo-needs-password`; current SSH user cannot stop/start services non-interactively |
|
||||
| BLOCKED | FAIL-002 CDR Worker stop/recover | Same sudo blocker |
|
||||
| BLOCKED | FAIL-003 MySQL short outage | Same sudo blocker |
|
||||
| BLOCKED | FAIL-004 Redis short outage | Same sudo blocker |
|
||||
|
||||
## Findings
|
||||
|
||||
- CPS burst behavior needs review: rate limiting appears to affect in-dialog BYE requests after the INVITE has already succeeded with `200 OK`. The system recovers for subsequent calls, but BYE `403 Rate Limited` can leave call teardown semantics ambiguous.
|
||||
- Service-stop fault tests remain blocked until non-interactive sudo is available or the sudo password is provided through an approved secure channel. I did not attempt to guess or bypass sudo.
|
||||
|
||||
## Final State
|
||||
|
||||
- B services checked active after the run.
|
||||
- HTTPS smoke after the run passed.
|
||||
- No service was left intentionally stopped.
|
||||
@@ -0,0 +1,52 @@
|
||||
# Remote Recordings, Playback, and Quality Test Report
|
||||
|
||||
Date: 2026-06-29T05:40:18.380Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | admin can login | status=200, duration=944ms |
|
||||
| PASS | admin login returns access token | tokenLength=296 |
|
||||
| PASS | low-privilege user can login for RBAC checks | status=200, duration=608ms |
|
||||
| PASS | low-privilege user cannot list recordings | status=403, duration=465ms |
|
||||
| PASS | low-privilege user cannot list quality rules | status=403, duration=380ms |
|
||||
| PASS | invalid recording status is rejected | status=400, duration=865ms |
|
||||
| PASS | invalid recording status returns RECORDING_STATUS_INVALID | code=RECORDING_STATUS_INVALID |
|
||||
| PASS | invalid recording list limit is rejected | status=400, duration=383ms |
|
||||
| PASS | invalid recording limit returns INTEGER_INVALID | code=INTEGER_INVALID |
|
||||
| PASS | READY recordings can be listed | status=200, duration=1272ms |
|
||||
| PASS | recording list shape is valid | count=20 |
|
||||
| PASS | recording detail can be fetched | status=200, duration=2056ms |
|
||||
| PASS | recording detail matches list item | id=rec_3329d4ba78c441f19ca3ca0dc241758c, reviews=0 |
|
||||
| PASS | READY recording playback returns X-Accel response or served media | status=200, expected=200/206, duration=5094ms |
|
||||
| PASS | playback response avoids real filesystem path exposure | xAccel=n/a, contentType=audio/wav |
|
||||
| PASS | low-privilege user cannot play recording | status=403, duration=379ms |
|
||||
| PASS | decimal review score is rejected by current API | status=400, duration=394ms |
|
||||
| PASS | decimal review score returns INTEGER_INVALID | code=INTEGER_INVALID |
|
||||
| PASS | invalid review result is rejected | status=400, duration=1213ms |
|
||||
| PASS | invalid review result returns QUALITY_REVIEW_RESULT_INVALID | code=QUALITY_REVIEW_RESULT_INVALID |
|
||||
| PASS | low-privilege user cannot save review | status=403, duration=1109ms |
|
||||
| PASS | quality review can be saved | status=200, duration=392ms |
|
||||
| PASS | quality review contains expected score/result/tags | score=88, result=ISSUE, tags=["noise","script"] |
|
||||
| PASS | reviewed recording list can be filtered | status=200, duration=889ms |
|
||||
| PASS | reviewed list contains reviewed recording | count=3 |
|
||||
| PASS | missing recording playback returns 404 | status=404, duration=402ms |
|
||||
| PASS | missing recording playback returns RECORDING_NOT_READY | code=RECORDING_NOT_READY |
|
||||
| PASS | invalid quality sampling ratio is rejected | status=400, duration=415ms |
|
||||
| PASS | invalid ratio returns QUALITY_RATIO_INVALID | code=QUALITY_RATIO_INVALID |
|
||||
| PASS | quality sampling rule is created | status=201, duration=521ms |
|
||||
| PASS | quality sampling rule has 100 percent ratio | ruleId=qsr_dfdc7cbfa8254a90848bd599e5bb, ratio=100.00, status=ENABLED |
|
||||
| PASS | quality sampling rule can be disabled | status=201, duration=970ms |
|
||||
| PASS | disabled quality rule status is DISABLED | status=DISABLED |
|
||||
| PASS | quality sampling rule can be enabled | status=201, duration=1030ms |
|
||||
| PASS | enabled quality rule status is ENABLED | status=ENABLED |
|
||||
| PASS | recording list includes stable sampling payload after rule change | status=200, duration=1813ms |
|
||||
| PASS | sampling payload shape is present | count=5 |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted.
|
||||
- Recording Worker file movement, checksum mismatch retention, source cleanup, and browser Range playback need A/B filesystem or browser-side verification.
|
||||
- Current API accepts integer review scores only; decimal score examples from the plan are asserted as rejected by this deployed service.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T04:58:50.321Z
|
||||
Base URL: https://100.90.90.91
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| FAIL | / returns 200 | Request timed out after 10000ms |
|
||||
| FAIL | frontend HTML contains app root | contentType=, bytes=0 |
|
||||
| FAIL | /api/v2/health/live returns 200 | Request timed out after 10000ms |
|
||||
| FAIL | live health reports ok | body=null |
|
||||
| FAIL | /api/v2/health/ready returns 200 | Request timed out after 10000ms |
|
||||
| FAIL | ready health reports database and redis ok | body=null |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=5795ms |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=9f416a91-55b6-423b-bcce-a554c9c8a0f3, expiresAt=2026-06-29T05:03:45.635Z |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=0, duration=10048ms, contentType=n/a
|
||||
- /api/v2/health/live: status=0, duration=10014ms, contentType=n/a
|
||||
- /api/v2/health/ready: status=0, duration=10009ms, contentType=n/a
|
||||
- /api/v2/auth/captcha: status=200, duration=5795ms, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T04:59:32.371Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=4433ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=434, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=558ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T04:59:25.206Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=970ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T04:59:26.180Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=2232ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=39237aa0-fecc-4529-a1ef-63484e303e6f, expiresAt=2026-06-29T05:04:27.702Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=4433ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=558ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=970ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=2232ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T06:03:57.618Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=3727ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=434, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=640ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T06:03:52.452Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=703ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T06:03:53.162Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=559ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=cb19317a-2c46-4a16-b743-48e918856745, expiresAt=2026-06-29T06:08:53.546Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=3727ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=640ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=703ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=559ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T06:29:20.572Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=1886ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=434, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=576ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T06:29:13.960Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=1953ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T06:29:14.536Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=608ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=31787ad3-c22c-4e87-9fec-6b0ff0e289d0, expiresAt=2026-06-29T06:34:16.507Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=1886ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=576ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=1953ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=608ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T06:40:35.637Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=3959ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=434, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=1537ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T06:40:27.517Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=1801ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T06:40:29.889Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=1477ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=99000b78-6bfd-42d4-80a2-9412dee38796, expiresAt=2026-06-29T06:45:30.853Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=3959ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=1537ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=1801ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=1477ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T07:18:37.925Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=2367ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=434, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=751ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T07:18:31.443Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=636ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T07:18:31.841Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=2012ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=aa4e3357-09da-4932-bad0-515a65986984, expiresAt=2026-06-29T07:23:32.938Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=2367ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=751ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=636ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=2012ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T07:40:52.298Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=2220ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=434, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=423ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T07:40:46.672Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=425ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T07:40:47.093Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=1375ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=24741c6c-8af6-4b26-a519-568b975e6b33, expiresAt=2026-06-29T07:45:48.366Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=2220ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=423ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=425ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=1375ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T07:51:38.171Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=2931ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=434, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=613ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T07:51:32.713Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=420ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T07:51:33.130Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=1217ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=28804ba6-99f0-4cdd-a966-8878ccd9abdc, expiresAt=2026-06-29T07:56:33.737Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=2931ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=613ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=420ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=1217ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T07:55:04.361Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=2948ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=422, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=851ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T07:54:58.998Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=425ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T07:54:59.434Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=1103ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=201d00b8-4096-4e9b-a478-09f38e8507e7, expiresAt=2026-06-29T08:00:00.361Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=2948ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=851ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=425ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=1103ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T08:09:17.242Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=3371ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=422, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=461ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T08:09:11.715Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=604ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T08:09:12.137Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=1123ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=58d3d4a2-6f71-4a78-a102-995ae8ebe444, expiresAt=2026-06-29T08:14:12.744Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=3371ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=461ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=604ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=1123ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T09:47:44.237Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=100ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=422, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=17ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T09:47:40.645Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=17ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T09:47:40.663Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=14ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=e1750f45-4291-4e38-b949-4f1332525147, expiresAt=2026-06-29T09:52:40.680Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=100ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=17ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=17ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=14ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T10:11:22.445Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=1632ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=422, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=1227ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T10:11:14.818Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=2785ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T10:11:17.451Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=1161ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=f1e5fa0e-ffc1-4ec5-b193-d9551d47eae5, expiresAt=2026-06-29T10:16:18.141Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=1632ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=1227ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=2785ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=1161ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T10:34:20.124Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=5834ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=422, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=1112ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T10:34:18.013Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=869ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-29T10:34:18.683Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=1078ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=1ee70823-7d33-4647-82e6-aa0099364891, expiresAt=2026-06-29T10:39:19.553Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=5834ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=1112ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=869ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=1078ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-30T01:28:30.863Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=1035ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=422, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=296ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-30T01:28:30.512Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=314ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-30T01:28:30.820Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=410ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=ded8cb2e-9ccc-4e5d-90f0-b4e0e0187a47, expiresAt=2026-06-30T01:33:31.152Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=1035ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=296ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=314ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=410ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-30T02:44:12.572Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=5040ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=466, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=324ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-30T02:44:12.723Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=161ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-30T02:44:12.890Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=271ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=784f66e9-ac29-4fa2-a330-aeac063e5ea1, expiresAt=2026-06-30T02:49:13.159Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=5040ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=324ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=161ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=271ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,24 @@
|
||||
# Remote Smoke Test Report
|
||||
|
||||
Date: 2026-06-30T03:11:46.183Z
|
||||
Base URL: https://100.90.90.91
|
||||
Timeout: 30000ms
|
||||
Attempts: 2
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | / returns 200 | status=200, duration=1652ms, attempt=1 |
|
||||
| PASS | frontend HTML contains app root | contentType=text/html, bytes=466, attempt=1 |
|
||||
| PASS | /api/v2/health/live returns 200 | status=200, duration=319ms, attempt=1 |
|
||||
| PASS | live health reports ok | body={"status":"ok","service":"api","timestamp":"2026-06-30T03:11:45.886Z","checks":{"process":"ok"}} |
|
||||
| PASS | /api/v2/health/ready returns 200 | status=200, duration=301ms, attempt=1 |
|
||||
| PASS | ready health reports database and redis ok | body={"status":"ok","service":"api","timestamp":"2026-06-30T03:11:46.200Z","checks":{"config":"ok","database":"ok","redis":"ok"}} |
|
||||
| PASS | /api/v2/auth/captcha returns 200 | status=200, duration=449ms, attempt=1 |
|
||||
| PASS | captcha endpoint returns id, image, and expiry | captchaId=713febe8-036e-4596-b5a5-a8ad95e42a6d, expiresAt=2026-06-30T03:16:46.503Z, attempt=1 |
|
||||
|
||||
## Raw Endpoints
|
||||
|
||||
- /: status=200, duration=1652ms, attempt=1, contentType=text/html
|
||||
- /api/v2/health/live: status=200, duration=319ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/health/ready: status=200, duration=301ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
- /api/v2/auth/captcha: status=200, duration=449ms, attempt=1, contentType=application/json; charset=utf-8
|
||||
@@ -0,0 +1,49 @@
|
||||
# Remote Vendors, Vendor Gateways, and Landing Line Groups Test Report
|
||||
|
||||
Date: 2026-06-29T05:28:04.913Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
Vendor Name: 自动化8.4供应商
|
||||
Line Group Name: 自动化8.4线路组
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | admin can login | status=200, duration=791ms |
|
||||
| PASS | admin login returns access token | tokenLength=296 |
|
||||
| PASS | low-privilege user can login for RBAC checks | status=200, duration=624ms |
|
||||
| PASS | low-privilege user cannot list vendors | status=403, duration=388ms |
|
||||
| PASS | low-privilege user cannot list line groups | status=403, duration=381ms |
|
||||
| PASS | invalid vendor is rejected | status=400, duration=382ms |
|
||||
| PASS | vendor is created | status=201, duration=416ms |
|
||||
| PASS | vendor has expected credit limit | vendorId=ven_a81199989064479697afadcfdd9b, creditLimit=200.000000 |
|
||||
| PASS | invalid vendor gateway host is rejected | status=400, duration=400ms |
|
||||
| PASS | invalid host returns HOST_INVALID | code=HOST_INVALID |
|
||||
| PASS | weak SIP password is rejected | status=400, duration=384ms |
|
||||
| PASS | primary vendor gateway is created | status=201, duration=602ms |
|
||||
| PASS | primary gateway has child config | codecs=2, prefixRules=2, callerRewrite=1 |
|
||||
| PASS | backup vendor gateway is created | status=201, duration=977ms |
|
||||
| PASS | vendor gateway can be disabled | status=201, duration=601ms |
|
||||
| PASS | disabled vendor gateway status is DISABLED | status=DISABLED |
|
||||
| PASS | vendor gateway can be enabled | status=201, duration=745ms |
|
||||
| PASS | enabled vendor gateway status is ENABLED | status=ENABLED |
|
||||
| PASS | line group is created | status=201, duration=436ms |
|
||||
| PASS | primary line group item is added | status=201, expected=201, duration=412ms |
|
||||
| PASS | backup line group item is added | status=201, expected=201, duration=420ms |
|
||||
| PASS | line group detail can be fetched | status=200, duration=387ms |
|
||||
| PASS | line group contains two enabled items | enabledItemCount=2, itemCount=2 |
|
||||
| PASS | line group items can be reordered | status=201, duration=404ms |
|
||||
| PASS | reorder preserves item set | before=2, after=2 |
|
||||
| PASS | duplicate line group gateway item is rejected | status=409, duration=406ms |
|
||||
| PASS | vendor gateway referenced by line group cannot be deleted | status=400, duration=391ms |
|
||||
| PASS | referenced gateway returns VENDOR_GATEWAY_IN_LINE_GROUP | code=VENDOR_GATEWAY_IN_LINE_GROUP |
|
||||
| PASS | line group can be disabled | status=201, duration=395ms |
|
||||
| PASS | disabled line group status is DISABLED | status=DISABLED |
|
||||
| PASS | line group can be enabled | status=201, duration=965ms |
|
||||
| PASS | enabled line group status is ENABLED | status=ENABLED |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted.
|
||||
- Vendor gateway and line group mutations enqueue config outbox events server-side.
|
||||
- Config publication manifest is not exposed by the black-box API; DB or Redis observation is required to assert worker publication directly.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Remote Vendors, Vendor Gateways, and Landing Line Groups Test Report
|
||||
|
||||
Date: 2026-06-29T05:28:35.481Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Low-Privilege Username: codex.low
|
||||
Vendor Name: 自动化8.4供应商
|
||||
Line Group Name: 自动化8.4线路组
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | admin can login | status=200, duration=442ms |
|
||||
| PASS | admin login returns access token | tokenLength=296 |
|
||||
| PASS | low-privilege user can login for RBAC checks | status=200, duration=429ms |
|
||||
| PASS | low-privilege user cannot list vendors | status=403, duration=381ms |
|
||||
| PASS | low-privilege user cannot list line groups | status=403, duration=384ms |
|
||||
| PASS | invalid vendor is rejected | status=400, duration=383ms |
|
||||
| PASS | vendor is updated | status=200, duration=413ms |
|
||||
| PASS | vendor has expected credit limit | vendorId=ven_a81199989064479697afadcfdd9b, creditLimit=200.000000 |
|
||||
| PASS | invalid vendor gateway host is rejected | status=400, duration=394ms |
|
||||
| PASS | invalid host returns HOST_INVALID | code=HOST_INVALID |
|
||||
| PASS | weak SIP password is rejected | status=400, duration=383ms |
|
||||
| PASS | primary vendor gateway is updated | status=200, duration=751ms |
|
||||
| PASS | primary gateway has child config | codecs=2, prefixRules=2, callerRewrite=1 |
|
||||
| PASS | backup vendor gateway is updated | status=200, duration=789ms |
|
||||
| PASS | vendor gateway can be disabled | status=201, duration=998ms |
|
||||
| PASS | disabled vendor gateway status is DISABLED | status=DISABLED |
|
||||
| PASS | vendor gateway can be enabled | status=201, duration=573ms |
|
||||
| PASS | enabled vendor gateway status is ENABLED | status=ENABLED |
|
||||
| PASS | line group is updated | status=200, duration=778ms |
|
||||
| PASS | primary line group item is updated | status=200, expected=200, duration=913ms |
|
||||
| PASS | backup line group item is updated | status=200, expected=200, duration=656ms |
|
||||
| PASS | line group detail can be fetched | status=200, duration=557ms |
|
||||
| PASS | line group contains two enabled items | enabledItemCount=2, itemCount=2 |
|
||||
| PASS | line group items can be reordered | status=201, duration=437ms |
|
||||
| PASS | reorder preserves item set | before=2, after=2 |
|
||||
| PASS | duplicate line group gateway item is rejected | status=409, duration=393ms |
|
||||
| PASS | vendor gateway referenced by line group cannot be deleted | status=400, duration=390ms |
|
||||
| PASS | referenced gateway returns VENDOR_GATEWAY_IN_LINE_GROUP | code=VENDOR_GATEWAY_IN_LINE_GROUP |
|
||||
| PASS | line group can be disabled | status=201, duration=623ms |
|
||||
| PASS | disabled line group status is DISABLED | status=DISABLED |
|
||||
| PASS | line group can be enabled | status=201, duration=1180ms |
|
||||
| PASS | enabled line group status is ENABLED | status=ENABLED |
|
||||
|
||||
## Notes
|
||||
|
||||
- Password and token values are intentionally omitted.
|
||||
- Vendor gateway and line group mutations enqueue config outbox events server-side.
|
||||
- Config publication manifest is not exposed by the black-box API; DB or Redis observation is required to assert worker publication directly.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Remote Web UI Test Report
|
||||
|
||||
Date: 2026-06-29T06:01:31.528Z
|
||||
Base URL: https://100.90.90.91
|
||||
Browser path: Browser plugin attempted first; fallback to local Chrome Playwright because in-app browser stopped at net::ERR_CERT_AUTHORITY_INVALID for the B HTTPS certificate.
|
||||
Viewport: 1440x900
|
||||
|
||||
## Findings
|
||||
|
||||
- Browser automation failed before completing all 8.8 checks: locator.click: Timeout 10000ms exceeded. Call log: [2m - waiting for getByRole('button', { name: '号码库' })[22m at D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\.node_repl_cell_6.mjs:101:55
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| FAIL | WEB-001 homepage renders login shell | title=LisgloSIPS - 聆界SIP管理平台, hasLogin=true |
|
||||
| PASS | WEB-001 access token is not present in URL before login | https://100.90.90.91/ |
|
||||
| PASS | WEB-001 admin login enters dashboard | url=https://100.90.90.91/ |
|
||||
| PASS | WEB-001 access token is not present in URL after login | https://100.90.90.91/ |
|
||||
| PASS | WEB-001 refresh restores authenticated dashboard | hasDashboard=true |
|
||||
| FAIL | WEB-005 admin sees all non-pending core menus | missing=号码库 |
|
||||
| FAIL | WEB automation completed without unhandled exception | locator.click: Timeout 10000ms exceeded.
|
||||
Call log:
|
||||
[2m - waiting for getByRole('button', { name: '号码库' })[22m
|
||||
|
|
||||
|
||||
## Screenshots
|
||||
|
||||
- Admin dashboard: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060046Z_admin-dashboard.png
|
||||
- Low-privilege nav: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060046Z_low-nav.png
|
||||
- Logout/login page: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060046Z_logout.png
|
||||
|
||||
## Notes
|
||||
|
||||
- CAPTCHA was read from the page image data URL with explicit user permission for this test run.
|
||||
- WEB-002 forced API 500/network-failure states and WEB-003 dedicated empty-data states were not injected against B to avoid disturbing the shared service.
|
||||
- WEB-006 was checked read-only from the served homepage; no release switch or deployment mutation was performed.
|
||||
|
After Width: | Height: | Size: 93 KiB |
@@ -0,0 +1,30 @@
|
||||
# Remote Web UI Test Report
|
||||
|
||||
Date: 2026-06-29T06:03:37.427Z
|
||||
Base URL: https://100.90.90.91
|
||||
Browser path: Browser plugin attempted first; fallback to local Chrome Playwright because in-app browser stopped at net::ERR_CERT_AUTHORITY_INVALID for the B HTTPS certificate.
|
||||
Viewport: 1440x900
|
||||
|
||||
## Findings
|
||||
|
||||
- Browser automation failed before completing all 8.8 checks: page.goto: Timeout 30000ms exceeded. Call log: [2m - navigating to "https://100.90.90.91/", waiting until "domcontentloaded"[22m at D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\.node_repl_cell_7.mjs:79:17
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| FAIL | WEB automation completed without unhandled exception | page.goto: Timeout 30000ms exceeded.
|
||||
Call log:
|
||||
[2m - navigating to "https://100.90.90.91/", waiting until "domcontentloaded"[22m
|
||||
|
|
||||
|
||||
## Screenshots
|
||||
|
||||
- Admin dashboard: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060305Z_admin-dashboard.png
|
||||
- Low-privilege nav: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060305Z_low-nav.png
|
||||
- Logout/login page: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060305Z_logout.png
|
||||
|
||||
## Notes
|
||||
|
||||
- CAPTCHA was read from the page image data URL with explicit user permission for this test run.
|
||||
- Initial unauthenticated /auth/refresh 401 console noise and navigation-cancelled net::ERR_ABORTED requests were excluded from console/network health because they are expected during login and rapid page switching.
|
||||
- WEB-002 forced API 500/network-failure states and WEB-003 dedicated empty-data states were not injected against B to avoid disturbing the shared service.
|
||||
- WEB-006 was checked read-only from the served homepage; no release switch or deployment mutation was performed.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Remote Web UI Test Report
|
||||
|
||||
Date: 2026-06-29T06:07:19.550Z
|
||||
Base URL: https://100.90.90.91
|
||||
Browser path: Browser plugin attempted first; fallback to local Chrome Playwright because in-app browser stopped at net::ERR_CERT_AUTHORITY_INVALID for the B HTTPS certificate.
|
||||
Viewport: 1440x900
|
||||
|
||||
## Findings
|
||||
|
||||
- Admin menu is missing expected core entries: Missing: 号码库.
|
||||
- Browser automation failed before completing all 8.8 checks: page.waitForSelector: Timeout 30000ms exceeded. Call log: [2m - waiting for locator('input[autocomplete="username"]') to be visible[22m at login883 (D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\.node_repl_cell_9.mjs:68:14) at async D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\.node_repl_cell_9.mjs:149:3
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | WEB-001 homepage renders login shell and captcha | title=LisgloSIPS - 聆界SIP管理平台, hasLogin=true |
|
||||
| PASS | WEB-001 access token is not present in URL before login | https://100.90.90.91/ |
|
||||
| PASS | WEB-001 admin login enters dashboard | url=https://100.90.90.91/ |
|
||||
| PASS | WEB-001 access token is not present in URL after login | https://100.90.90.91/ |
|
||||
| PASS | WEB-001 refresh restores authenticated dashboard | hasDashboard=true |
|
||||
| FAIL | WEB-005 admin sees all non-pending core menus | missing=号码库 |
|
||||
| FAIL | WEB-005 admin can switch available core pages without blank screen | failed=概览 Dashboard(textLength=604),客户管理(textLength=337),客户网关管理(textLength=346),业务前缀管理(textLength=353),充值记录(textLength=358),供应商管理(textLength=307),落地网关管理(textLength=376),落地线路组(textLength=310),当前通话(textLength=396),话单中心(textLength=773),质检中心(textLength=360),用户管理(textLength=575),角色与权限(textLength=541),操作日志(textLength=10683) |
|
||||
| PASS | WEB-004 customer empty form stays on validation surface | modalBefore=true, modalAfter=true |
|
||||
| FAIL | WEB-001 logout button is visible | 退出登录 count=0 |
|
||||
| FAIL | WEB automation completed without unhandled exception | page.waitForSelector: Timeout 30000ms exceeded.
|
||||
Call log:
|
||||
[2m - waiting for locator('input[autocomplete="username"]') to be visible[22m
|
||||
|
|
||||
|
||||
## Screenshots
|
||||
|
||||
- Admin dashboard: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060555Z_admin-dashboard.png
|
||||
- Low-privilege nav: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060555Z_low-nav.png
|
||||
- Logout/login page: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060555Z_logout.png
|
||||
|
||||
## Notes
|
||||
|
||||
- CAPTCHA was read from the page image data URL with explicit user permission for this test run.
|
||||
- Initial unauthenticated /auth/refresh 401 console noise and navigation-cancelled net::ERR_ABORTED requests were excluded from console/network health because they are expected during login and rapid page switching.
|
||||
- WEB-002 forced API 500/network-failure states and WEB-003 dedicated empty-data states were not injected against B to avoid disturbing the shared service.
|
||||
- WEB-006 was checked read-only from the served homepage; no release switch or deployment mutation was performed.
|
||||
|
After Width: | Height: | Size: 94 KiB |
@@ -0,0 +1,43 @@
|
||||
# Remote Web UI Test Report
|
||||
|
||||
Date: 2026-06-29T06:10:12.850Z
|
||||
Base URL: https://100.90.90.91
|
||||
Browser path: Browser plugin attempted first; fallback to local Chrome Playwright because in-app browser stopped at net::ERR_CERT_AUTHORITY_INVALID for the B HTTPS certificate.
|
||||
Viewport: 1440x900
|
||||
|
||||
## Findings
|
||||
|
||||
- Admin menu is missing expected core entries: Missing: 号码库.
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | WEB-001 homepage renders login shell and captcha | title=LisgloSIPS - 聆界SIP管理平台 |
|
||||
| PASS | WEB-001 access token is not present in URL before login | https://100.90.90.91/ |
|
||||
| PASS | WEB-001 admin login enters dashboard | url=https://100.90.90.91/ |
|
||||
| PASS | WEB-001 access token is not present in URL after login | https://100.90.90.91/ |
|
||||
| PASS | WEB-001 refresh restores authenticated dashboard | hasDashboard=true |
|
||||
| FAIL | WEB-005 admin sees all non-pending core menus | missing=号码库 |
|
||||
| FAIL | WEB-005 admin can switch available core pages without blank screen | failed=概览 Dashboard(blank/login),客户管理(blank/login),客户网关管理(blank/login),业务前缀管理(blank/login),充值记录(blank/login),供应商管理(blank/login),落地网关管理(blank/login),落地线路组(blank/login),当前通话(blank/login),话单中心(blank/login),质检中心(blank/login),用户管理(blank/login),角色与权限(blank/login),操作日志(blank/login) |
|
||||
| FAIL | WEB-002 navigation does not show API unavailable state | pages=业务前缀管理 |
|
||||
| PASS | WEB-004 customer empty form stays on validation surface | modalBefore=true, modalAfter=true |
|
||||
| PASS | WEB-001 logout button is visible | 退出 count=1 |
|
||||
| PASS | WEB-001 logout returns to login and clears access token | tokenCleared=true |
|
||||
| PASS | WEB-005 low-privilege menu is permission-pruned | visibleForbidden=none, labels=概概览 Dashboard/退出/刷新指标 |
|
||||
| PASS | WEB-002 low-privilege dashboard does not show bulk 403 error state | hasApiError=false, hasNoPermission=false |
|
||||
| PASS | WEB-006 HTTPS homepage returns HTML with hashed assets | status=200, assets=/assets/index-CBRZZA7t.js,/assets/index-B2uYBtS3.css |
|
||||
| PASS | WEB-006 homepage does not reference access tokens or env files | bytes=422 |
|
||||
| PASS | WEB console has no relevant error or warning entries | none |
|
||||
| PASS | WEB network has no relevant failed requests | none |
|
||||
|
||||
## Screenshots
|
||||
|
||||
- Admin dashboard: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060852Z_admin-dashboard.png
|
||||
- Low-privilege nav: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060852Z_low-nav.png
|
||||
- Logout/login page: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T060852Z_logout.png
|
||||
|
||||
## Notes
|
||||
|
||||
- CAPTCHA was read from the page image data URL with explicit user permission for this test run.
|
||||
- Initial unauthenticated /auth/refresh 401 console noise and navigation-cancelled net::ERR_ABORTED requests were excluded from console/network health because they are expected during login and rapid page switching.
|
||||
- WEB-002 forced API 500/network-failure states and WEB-003 dedicated empty-data states were not injected against B to avoid disturbing the shared service.
|
||||
- WEB-006 was checked read-only from the served homepage; no release switch or deployment mutation was performed.
|
||||
|
After Width: | Height: | Size: 94 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 72 KiB |
@@ -0,0 +1,43 @@
|
||||
# Remote Web UI Test Report
|
||||
|
||||
Date: 2026-06-29T06:12:23.366Z
|
||||
Base URL: https://100.90.90.91
|
||||
Browser path: Browser plugin attempted first; fallback to local Chrome Playwright because in-app browser stopped at net::ERR_CERT_AUTHORITY_INVALID for the B HTTPS certificate.
|
||||
Viewport: 1440x900
|
||||
|
||||
## Findings
|
||||
|
||||
- Admin menu is missing expected core entries: Missing: 号码库.
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | WEB-001 homepage renders login shell and captcha | title=LisgloSIPS - 聆界SIP管理平台 |
|
||||
| PASS | WEB-001 access token is not present in URL before login | https://100.90.90.91/ |
|
||||
| PASS | WEB-001 admin login enters dashboard | url=https://100.90.90.91/ |
|
||||
| PASS | WEB-001 access token is not present in URL after login | https://100.90.90.91/ |
|
||||
| PASS | WEB-001 refresh restores authenticated dashboard | hasDashboard=true |
|
||||
| FAIL | WEB-005 admin sees all non-pending core menus | missing=号码库 |
|
||||
| PASS | WEB-005 admin can switch available core pages without blank screen | failed=none |
|
||||
| PASS | WEB-002 navigation does not show API unavailable state | pages=none |
|
||||
| PASS | WEB-004 customer empty form stays on validation surface | modalBefore=true, modalAfter=true |
|
||||
| PASS | WEB-001 logout button is visible | 退出 count=1 |
|
||||
| PASS | WEB-001 logout returns to login and clears access token | tokenCleared=true |
|
||||
| PASS | WEB-005 low-privilege menu is permission-pruned | visibleForbidden=none, labels=概概览 Dashboard/退出/刷新指标 |
|
||||
| PASS | WEB-002 low-privilege dashboard does not show bulk 403 error state | hasApiError=false, hasNoPermission=false |
|
||||
| PASS | WEB-006 HTTPS homepage returns HTML with hashed assets | status=200, assets=/assets/index-CBRZZA7t.js,/assets/index-B2uYBtS3.css |
|
||||
| PASS | WEB-006 homepage does not reference access tokens or env files | bytes=422 |
|
||||
| PASS | WEB console has no relevant error or warning entries | none |
|
||||
| PASS | WEB network has no relevant failed requests | none |
|
||||
|
||||
## Screenshots
|
||||
|
||||
- Admin dashboard: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T061117Z_admin-dashboard.png
|
||||
- Low-privilege nav: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T061117Z_low-nav.png
|
||||
- Logout/login page: D:\HuaweiMoveData\Users\hectorzhao\Documents\自建软交换\tests\reports\REMOTE_WEB_UI_20260629T061117Z_logout.png
|
||||
|
||||
## Notes
|
||||
|
||||
- CAPTCHA was read from the page image data URL with explicit user permission for this test run.
|
||||
- Initial unauthenticated /auth/refresh 401 console noise and navigation-cancelled net::ERR_ABORTED requests were excluded from console/network health because they are expected during login and rapid page switching.
|
||||
- WEB-002 forced API 500/network-failure states and WEB-003 dedicated empty-data states were not injected against B to avoid disturbing the shared service.
|
||||
- WEB-006 was checked read-only from the served homepage; no release switch or deployment mutation was performed.
|
||||
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 80 KiB |
@@ -0,0 +1,57 @@
|
||||
# Remote Web UI Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T10:04:19.835Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Headless: true
|
||||
Browser Channel: chrome
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | API login succeeds for browser smoke | status=200, captchaLength=5, permissionCount=26 |
|
||||
| PASS | UI login succeeds before menu smoke | captchaLength=5 |
|
||||
| PASS | 概览 Dashboard renders without browser errors | textLength=500, api-ok, authenticated, errors=0 |
|
||||
| PASS | 概览 Dashboard action 刷新 works without browser errors | errors=0 |
|
||||
| PASS | 客户管理 renders without browser errors | textLength=190, api-ok, authenticated, errors=0 |
|
||||
| PASS | 客户管理 safe action is available | no visible enabled action among 编辑; skipped |
|
||||
| PASS | 客户网关管理 renders without browser errors | textLength=536, api-ok, authenticated, errors=0 |
|
||||
| FAIL | 客户网关管理 action 编辑 works without browser errors | errors=Error: Minified React error #137; visit https://reactjs.org/docs/error-decoder.html?invariant=137&args[]=input for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
|
||||
at ws (https://100.90.90.91/assets/index-D90saQl_.js:37:7909)
|
||||
at Wp (https://100.90.90.91/assets/index-D90saQl_.js:40:17537)
|
||||
at kd (https://100.90.90.91/assets/index-D90saQl_.js:40:40074)
|
||||
at wd (https://100.90.90.91/assets/index-D90saQl_.js:40:39827)
|
||||
at Zp (https://100.90.90.91/assets/index-D90saQl_.js:40:39694)
|
||||
at ca (https://100.90.90.91/assets/index-D90saQl_.js:40:39547)
|
||||
at ti (https://100.90.90.91/assets/index-D90saQl_.js:40:35914)
|
||||
at ou (https://100.90.90.91/assets/index-D90saQl_.js:40:36717)
|
||||
at Rn (https://100.90.90.91/assets/index-D90saQl_.js:38:3274)
|
||||
at https://100.90.90.91/assets/index-D90saQl_.js:40:34246 \|\| Error: Minified React error #137; visit https://reactjs.org/docs/error-decoder.html?invariant=137&args[]=input for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
|
||||
at ws (https://100.90.90.91/assets/index-D90saQl_.js:37:7909)
|
||||
at Wp (https://100.90.90.91/assets/index-D90saQl_.js:40:17537)
|
||||
at kd (https://100.90.90.91/assets/index-D90saQl_.js:40:40074)
|
||||
at wd (https://100.90.90.91/assets/index-D90saQl_.js:40:39827)
|
||||
at Zp (https://100.90.90.91/assets/index-D90saQl_.js:40:39694)
|
||||
at ca (https://100.90.90.91/assets/index-D90saQl_.js:40:39547)
|
||||
at ti (https://100.90.90.91/assets/index-D90saQl_.js:40:35914)
|
||||
at ou (https://100.90.90.91/assets/index-D90saQl_.js:40:36717)
|
||||
at Rn (https://100.90.90.91/assets/index-D90saQl_.js:38:3274)
|
||||
at https://100.90.90.91/assets/index-D90saQl_.js:40:34246 \|\| Minified React error #137; visit https://reactjs.org/docs/error-decoder.html?invariant=137&args[]=input for the full message or use the non-minified dev environment for full errors and additional helpful warnings. |
|
||||
| FAIL | 业务前缀管理 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 充值记录 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 供应商管理 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 落地网关管理 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 落地线路组 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 号码库 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 当前通话 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 话单中心 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 质检中心 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 用户管理 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 角色与权限 menu is visible | menu button not found or not visible |
|
||||
| FAIL | 操作日志 menu is visible | menu button not found or not visible |
|
||||
|
||||
## Guardrails
|
||||
|
||||
- Fails on browser `pageerror` and console `error` events.
|
||||
- Fails when a navigated page is blank, falls back to login, or shows `API 数据不可用`.
|
||||
- After each menu render, clicks one safe primary row action when available, such as edit, detail, or refresh.
|
||||
- Password and token values are intentionally omitted.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Remote Web UI Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T10:19:11.811Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Headless: true
|
||||
Browser Channel: chrome
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | API login succeeds for browser smoke | status=200, captchaLength=5, permissionCount=26 |
|
||||
| PASS | UI login succeeds before menu smoke | captchaLength=5 |
|
||||
| PASS | 概览 Dashboard renders without browser errors | textLength=500, api-ok, authenticated, errors=0 |
|
||||
| PASS | 概览 Dashboard action 刷新 works without browser errors | errors=0 |
|
||||
| PASS | 客户管理 renders without browser errors | textLength=190, api-ok, authenticated, errors=0 |
|
||||
| PASS | 客户管理 safe action is available | no visible enabled action among 编辑; skipped |
|
||||
| PASS | 客户网关管理 renders without browser errors | textLength=536, api-ok, authenticated, errors=0 |
|
||||
| PASS | 客户网关管理 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 业务前缀管理 renders without browser errors | textLength=239, api-ok, authenticated, errors=0 |
|
||||
| PASS | 业务前缀管理 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 充值记录 renders without browser errors | textLength=1110, api-ok, authenticated, errors=0 |
|
||||
| PASS | 充值记录 safe action is available | no visible enabled action among 刷新; skipped |
|
||||
| PASS | 供应商管理 renders without browser errors | textLength=296, api-ok, authenticated, errors=0 |
|
||||
| PASS | 供应商管理 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 落地网关管理 renders without browser errors | textLength=492, api-ok, authenticated, errors=0 |
|
||||
| PASS | 落地网关管理 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 落地线路组 renders without browser errors | textLength=200, api-ok, authenticated, errors=0 |
|
||||
| PASS | 落地线路组 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 号码库 renders without browser errors | textLength=176, api-ok, authenticated, errors=0 |
|
||||
| PASS | 号码库 action 刷新 works without browser errors | errors=0 |
|
||||
| PASS | 当前通话 renders without browser errors | textLength=206, api-ok, authenticated, errors=0 |
|
||||
| PASS | 当前通话 action 刷新通话 works without browser errors | errors=0 |
|
||||
| PASS | 话单中心 renders without browser errors | textLength=6481, api-ok, authenticated, errors=0 |
|
||||
| PASS | 话单中心 safe action is available | no visible enabled action among 查看详情; skipped |
|
||||
| PASS | 质检中心 renders without browser errors | textLength=11656, api-ok, authenticated, errors=0 |
|
||||
| PASS | 质检中心 action 刷新 works without browser errors | errors=0 |
|
||||
| PASS | 用户管理 renders without browser errors | textLength=370, api-ok, authenticated, errors=0 |
|
||||
| PASS | 用户管理 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 角色与权限 renders without browser errors | textLength=335, api-ok, authenticated, errors=0 |
|
||||
| PASS | 角色与权限 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 操作日志 renders without browser errors | textLength=9746, api-ok, authenticated, errors=0 |
|
||||
| PASS | 操作日志 action 查看详情 works without browser errors | errors=0 |
|
||||
|
||||
## Guardrails
|
||||
|
||||
- Fails on browser `pageerror` and console `error` events.
|
||||
- Fails when a navigated page is blank, falls back to login, or shows `API 数据不可用`.
|
||||
- After each menu render, clicks one safe primary row action when available, such as edit, detail, or refresh.
|
||||
- Password and token values are intentionally omitted.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Remote Web UI Smoke Test Report
|
||||
|
||||
Date: 2026-06-29T10:40:40.403Z
|
||||
Base URL: https://100.90.90.91
|
||||
Username: admin
|
||||
Headless: true
|
||||
Browser Channel: chrome
|
||||
|
||||
| Result | Check | Detail |
|
||||
| --- | --- | --- |
|
||||
| PASS | API login succeeds for browser smoke | status=200, captchaLength=5, permissionCount=26 |
|
||||
| PASS | UI login succeeds before menu smoke | captchaLength=5 |
|
||||
| PASS | 概览 Dashboard renders without browser errors | textLength=500, api-ok, authenticated, errors=0 |
|
||||
| PASS | 概览 Dashboard action 刷新 works without browser errors | errors=0 |
|
||||
| PASS | 客户管理 renders without browser errors | textLength=614, api-ok, authenticated, errors=0 |
|
||||
| PASS | 客户管理 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 客户网关管理 renders without browser errors | textLength=480, api-ok, authenticated, errors=0 |
|
||||
| PASS | 客户网关管理 action 编辑 works without browser errors | errors=0, business-prefix-checkbox-toggle-ok: false->true->false |
|
||||
| PASS | 业务前缀管理 renders without browser errors | textLength=239, api-ok, authenticated, errors=0 |
|
||||
| PASS | 业务前缀管理 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 充值记录 renders without browser errors | textLength=1110, api-ok, authenticated, errors=0 |
|
||||
| PASS | 充值记录 safe action is available | no visible enabled action among 刷新; skipped |
|
||||
| PASS | 供应商管理 renders without browser errors | textLength=296, api-ok, authenticated, errors=0 |
|
||||
| PASS | 供应商管理 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 落地网关管理 renders without browser errors | textLength=492, api-ok, authenticated, errors=0 |
|
||||
| PASS | 落地网关管理 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 落地线路组 renders without browser errors | textLength=200, api-ok, authenticated, errors=0 |
|
||||
| PASS | 落地线路组 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 号码库 renders without browser errors | textLength=176, api-ok, authenticated, errors=0 |
|
||||
| PASS | 号码库 action 刷新 works without browser errors | errors=0 |
|
||||
| PASS | 当前通话 renders without browser errors | textLength=206, api-ok, authenticated, errors=0 |
|
||||
| PASS | 当前通话 action 刷新通话 works without browser errors | errors=0 |
|
||||
| PASS | 话单中心 renders without browser errors | textLength=6481, api-ok, authenticated, errors=0 |
|
||||
| PASS | 话单中心 safe action is available | no visible enabled action among 查看详情; skipped |
|
||||
| PASS | 质检中心 renders without browser errors | textLength=11656, api-ok, authenticated, errors=0 |
|
||||
| PASS | 质检中心 action 刷新 works without browser errors | errors=0 |
|
||||
| PASS | 用户管理 renders without browser errors | textLength=370, api-ok, authenticated, errors=0 |
|
||||
| PASS | 用户管理 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 角色与权限 renders without browser errors | textLength=335, api-ok, authenticated, errors=0 |
|
||||
| PASS | 角色与权限 action 编辑 works without browser errors | errors=0 |
|
||||
| PASS | 操作日志 renders without browser errors | textLength=9746, api-ok, authenticated, errors=0 |
|
||||
| PASS | 操作日志 action 查看详情 works without browser errors | errors=0 |
|
||||
|
||||
## Guardrails
|
||||
|
||||
- Fails on browser `pageerror` and console `error` events.
|
||||
- Fails when a navigated page is blank, falls back to login, or shows `API 数据不可用`.
|
||||
- After each menu render, clicks one safe primary row action when available, such as edit, detail, or refresh.
|
||||
- Password and token values are intentionally omitted.
|
||||