PHP 8 fixes, performance indexes, REST v3 expansion, modern SPA UI, webhooks/OIDC, MCP server#413
Open
hupark-seegene wants to merge 10 commits into
Conversation
- string_api.php: define LINKS_SAME_WINDOW / LINKS_NEW_WINDOW
(adapted from MantisBT, referenced but never defined — fatal on
PHP 8 when rendering any value containing a URL), replace removed
split() with explode(), pass -1 instead of null to preg_split()
- xmlrpc.class.php: fix (arrya) cast typo that was a parse error,
leaving the whole XML-RPC v1 API dead
- RestApiCustomExample.class.php: quote bare 'lib' constant
(fatal on load of REST v3 API)
- testplan.class.php: replace ${var} string interpolation
(deprecated in PHP 8.2)
- tcImport.php / tcCreateFromIssue.php / neverRunByPP.php: fix
optional-parameter-before-required declarations
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CAUVXjSm6HedDGCi8dkEZX
The dashboard/metrics queries filter executions by test plan and resolve the latest execution per test case version. The historic executions_idx1 index starts with tcversion_id, so plan-scoped scans degraded to full table scans (measured over 500k rows). - idx_exec_tplan_tcv_id (testplan_id, tcversion_id, id) backs latest-per-version lookups and flip/flaky analysis - idx_exec_tplan_ts (testplan_id, execution_ts) backs daily trends Measured on 500k executions: status totals 123ms -> 46ms when combined with a MAX(id) loose-index-scan query shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CAUVXjSm6HedDGCi8dkEZX
Webhooks: new lib/functions/webhook_api.php sends HMAC-SHA256-signed JSON POSTs (X-TestLink-Signature, GitHub-style) to URLs configured in $tlCfg->webhooks when executions are recorded (UI and API write paths). Best-effort with short timeouts so a dead receiver cannot block the user-facing operation. Disabled by default. OIDC: new generic OpenID Connect provider (Keycloak, Okta, Auth0, Azure AD v2, any spec-compliant IdP). Endpoints configurable explicitly or resolved from .well-known/openid-configuration. Identity is read from the userinfo endpoint over TLS, so no local JWT verification is required. Sample config in cfg/oauth_samples/. Also fixes an undefined $oauthCfg variable in the azuread branch of OAuth2Call.php. Reports: new "Execution Trend & Flaky Tests" report — daily executions by status as a dependency-free server-side SVG chart, plus a ranking of test case versions whose executions flip between pass and fail. Registered in the reports menu. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CAUVXjSm6HedDGCi8dkEZX
REST v3 additions backing the new UI (and useful standalone):
- POST /auth/login — exchanges login/password for the user's API key
(auth middleware now uses case-insensitive PSR-7 getHeaderLine()
and actually returns the 401 it builds)
- pagination for GET /testprojects/{mixedID}/testcases (?page=&limit=)
and fix for the route arg mismatch that broke it
- suites tree, suite test cases, test case detail (steps + recent
runs), test case update (steps replace), plan link, plan summary /
trend / flaky / execution queue / result matrix (by case and by
suite), builds by plan id
- plan status totals use a MAX(id) loose-index-scan + PK join so the
cost follows the number of test case versions, not executions;
flaky analysis is bounded to a configurable recent window
ui/: React 19 + Vite + TanStack Router/Query + Tailwind v4 SPA
covering the daily workflow — dashboard (verdict wall, trend, flaky),
test case browser with suite tree + case editor (steps CRUD, new
suite/case, add-to-plan), execution run queue with verdict recorder,
result matrix (at-a-glance by-suite ratio bars with drill-down to
case level), plans & builds management, reports. Screens deep-link
to each other (?caseId=). Dev: cd ui && npm run dev. Build output
ui/dist is served by the PHP web server as static files.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CAUVXjSm6HedDGCi8dkEZX
- REST: GET /users, POST /testplans/{id}/assign (replace-style
execution assignments on user_assignments, userID 0 unassigns),
queue gains assignee join and assignedTo filter,
GET /testplans/{id}/byTester and /byBuild (latest execution per
version+build, so re-runs don't double count)
- Run screen: assignee filter (everyone/unassigned/user), assignee
badge in the queue, assign-to select in the verdict recorder
- Reports screen: build comparison and by-tester tables
- ui/ i18n: built-in typed dictionary (no new dependency), locales
en / ko / vi, 108 keys each — the en dictionary is the source of
truth and tsc rejects incomplete translations; language switcher
in the sidebar, choice persisted, default from browser language
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CAUVXjSm6HedDGCi8dkEZX
REST v3:
- GET /testprojects/{id}/search — find cases by external id, name or
summary text, scoped to the project's (nested) suite subtree
- execution attachments: multipart upload, listing, and authenticated
binary download (the JSON content-type middleware now respects a
type set by the handler); case detail carries per-run attachments
- getPlanFlaky streams rows instead of materializing the window —
large windows used to exceed memory_limit on big installations
ui/:
- global search box in the header with live results and deep links
- evidence upload in the Run verdict recorder; attachment chips with
authenticated viewing in case detail recent runs
- Plans screen: create project, close/reopen builds
- CSV export for the case matrix and the by-tester report
- deep links now accept both quoted and bare caseId values
MCP:
- mcp/ — TypeScript Model Context Protocol server (stdio) exposing
19 agent-ergonomic tools over the REST API (search_cases, get_case,
create_case, record_execution, plan_status, plan_flaky, ...)
- .mcp.json — project-level registration for Claude Code
- .claude/agents/testlink-qa.md — QA operator subagent definition
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CAUVXjSm6HedDGCi8dkEZX
Requirements: - REST: req spec tree, spec/requirement creation (through the legacy requirement managers so revisions and version nodes stay correct), requirement detail, test case coverage link/unlink (idempotent), and a plan-scoped per-requirement verdict rollup that reuses the latest-execution loose-scan pattern - SPA /requirements: spec tree -> requirement list -> detail with covered cases (search-to-cover, unlink, deep links) plus the plan coverage panel with verdict ratio bars - note: requirement_spec_mgr::create()'s default $type references an undefined constant (PHP 8 fatal); the endpoint passes the type explicitly like every legacy caller does Admin: - REST: users (list now carries email/role/active), user creation (verified end-to-end: created user can authenticate), activate/ deactivate, project keywords list/create/delete (cleans keyword links like the legacy manager), platforms list/create, linked custom fields (read-only) - SPA /admin: Users / Keywords / Platforms / Custom fields tabs i18n: 63 new keys per locale (en/ko/vi). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CAUVXjSm6HedDGCi8dkEZX
…yword report
Documents:
- GET /testprojects/{id}/document?type=spec[&suiteID=] — printable,
self-contained HTML test specification (suite hierarchy, case
attributes, steps tables); whole-project output is capped with a
visible truncation note
- GET /testplans/{id}/document?type=report[&buildID=] — printable
test report: per-suite verdict summary plus per-case latest
verdicts with tester/date/notes
XML:
- GET /testsuites/{id}/xml reuses the legacy exporter classes, so
the schema stays byte-compatible with classic TestLink exports
(two sessionless-execution fixes: cwd-relative require in the
platform helper, and warning suppression)
- POST /testsuites/{id}/xml imports that same format (cases + steps,
duplicate names skipped); round-trip verified: export -> import ->
re-export with identical case and per-case step counts
Milestones & keyword report:
- GET/POST/DELETE milestones with plan progress (executed% / pass%)
computed via the latest-execution loose scan
- GET /testplans/{id}/byKeyword — per-keyword verdict rollup joined
through testcase_keywords
SPA: suite toolbar (export XML / spec document / import XML with
result flash), test report button on Reports, Milestones panel on
Plans, By-keyword panel on Reports. New strings in en/ko/vi.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CAUVXjSm6HedDGCi8dkEZX
Full description of the php8-modernization branch: base/after versions, before/after code for the key PHP 8 fixes and query reshapes, measured performance table (500k-execution dataset), feature inventory (webhooks, OIDC, REST v3 endpoints, SPA, MCP), installation additions, cautions, and before/after screenshots. The existing README is untouched and remains authoritative for classic TestLink. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CAUVXjSm6HedDGCi8dkEZX
On a high-latency link the dashboard was serialized into a 3-hop request waterfall (projects -> plans -> summary/trend/flaky), ~2.1s end to end even though each origin response is <10ms — the cost was three sequential round trips. The workspace now exposes the remembered project/plan ids from localStorage, so on a revisit the plans lookup and the dashboard queries fire immediately in parallel with the projects fetch instead of waiting for it. Measured: dashboard data ready 2135ms -> 787ms. Also: nginx serves the content-hashed /ui/dist/assets/ with a 1-year immutable cache (index.html stays no-cache), so revisits load the SPA shell from disk. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CAUVXjSm6HedDGCi8dkEZX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR modernizes TestLink 1.9.20 while keeping the legacy application fully intact — everything is additive. All changes were runtime-verified against a live instance seeded with 10,000 test cases / 500,000 executions. A detailed write-up with before/after code, measured numbers, install steps and cautions lives in
docs/modernization/MODERNIZATION.mdin this branch.What's inside (10 commits, reviewable independently)
ui/, ~103KB gz, served statically) covering dashboard, case authoring, requirements coverage, execution with evidence attachments and assignments, result matrix, plans/builds/milestones, reports with CSV, admin, global search. Localized en/ko/vi (typed dictionaries — an incomplete translation is a compile error).mcp/exposes 19 tools over the REST API for AI-assisted test management (Model Context Protocol, stdio), plus a ready-made Claude Code agent definition.Compatibility
Verification
php -l clean across first-party code; every endpoint curl-verified; SPA flows browser-verified; XML export/import round-trip compared equal; perf numbers measured on 500k executions.
Happy to split this into smaller PRs (the commits are already sliced that way) if that makes review easier.
🤖 Generated with Claude Code (Claude Fable 5)