Repository navigation
Remote Test Automation Execution Modernized
Modernization of Remote Test Automation Execution
(lib/testcases/tcExecute.php) — GitHub issue
#1587.
tcExecute.php was the last standalone lib/testcases/* controller still
rendering a full legacy page. It is replaced by a standalone Dashio page
(gui/templates/testcases/tcAutoExec.html) backed by a plain-PHP REST BFF
(api/tcautoexec/index.php). The ASIDE entry Test Case Design → Test
Automation Execution sits right after Test Automation Specification (both
gated on view_tc), and the legacy controller is kept as a session-guarded 302
shim.
URL: gui/templates/testcases/tcAutoExec.html?tproject_id=<id>&tplan_id=<id>
BFF API: api/tcautoexec/index.php
Rights: mgt_view_tc on the owning test project (fail closed — the
legacy controller had no rights check at all) → 401 anonymous / 403 no right /
404 unknown project or node / 400 bad level, node or project / 405 wrong method /
403 missing same-origin proof on the POST.







- What the screen does
- REST API Reference
- Legacy parity notes
- Bugs found and fixed
- i18n Keys
- Security
- Testing
| Feature | Legacy behavior | Modern implementation |
|---|---|---|
| Context | hidden form fields | context card: test project (read-only, with id), test plan, build, platform |
| Target | one flat "level" form | LEVEL select: Single test case / Test suite / Whole test project + the matching node select |
| Server visibility | only after the run | every node in the select is prefixed with its resolved server and its source (test case vs. suite custom fields) |
| Result list | one HTML table of raw XML rows | summary counters + per-case table: test case (deep link), server, status badge, result, message, notes |
| Statuses | rendered as text |
ANSWERED, CONFIG PROBLEMS, CONNECTION FAILURE as badges, localized |
| Volume | unlimited (browser timeout) | max 200 test cases per request + a truncation warning bar |
| No rights | form rendered anyway, submit failed | 403 rendered as an Access denied card |
Plan changes reload the build list (builds are project scoped) and the platform list (platforms are test-plan scoped) and re-fetch the node list.
{
"status": "ok",
"context": { "tproject_id": 107, "tproject_name": "AutoExec Demo",
"tplan_id": 108, "build_id": 13, "platform_id": 10,
"plans": [ ... ], "builds": [ ... ], "platforms": [ ... ] },
"levels": {
"testcase": [ { "id": 113, "name": "AX1587-1", "server": "http://127.0.0.1:9999/xmlrpc.php",
"server_source": "testcase", "server_host": "127.0.0.1" } ],
"testsuite": [ ... ],
"testproject": [ ... ]
}
}400 missing/unknown params · 401 anonymous · 403 no mgt_view_tc ·
404 unknown project · 405 non-GET.
Form-encoded body: {level, node_id, tproject_id, tplan_id, build_id, platform_id}.
{ "status": "ok",
"counters": { "total": 1, "ok": 1, "configProblems": 0,
"connectionFailure": 0, "failed": 0 },
"truncated": false,
"results": [ { "tcase_id": 113, "tcversion_id": 114, "name": "AX1587-1",
"server": "http://127.0.0.1:9999/xmlrpc.php",
"server_source": "testcase",
"status": "ok", "result_status": "answered",
"result": "PASSED", "result_label": "Passed",
"notes": "executed by the mock server for #113",
"message": "Mock execution finished: AX1587-1",
"scheduled": "now", "timestampISO": "2026-09-25T10:00:00+00:00" } ] }result_status / result_label come from taeResolveResultStatus(), which maps
the XML-RPC code through the legacy code_status table (p → passed,
f → failed, b → blocked). Unknown codes are reported verbatim, classified as
failed, and — since #1588 — without any PHP warning.
The remote call itself is the legacy executeTestCase()
(lib/functions/remote_exec.php), so the XML-RPC payload, the system status
handling and the audit trail are identical to 1.9.20. tplan_api_key is
resolved server-side only and never appears in any payload.
-
tc_server_host/tc_server_port/tc_server_pathon the test case (custom fields with thetc_prefix), else -
tsuite_server_host/tsuite_server_port/tsuite_server_pathon the test case's suite or any suite ancestor, else - nothing → the test case is reported as
CONFIG PROBLEMSwithout any remote call.
-
level=testsuitecollects the test cases of the suite and of every nested suite, ordered by spec order;level=testprojectdoes the same from the project root. - The legacy
subtreewalk descends into the steps of every test case and askstree::$node_tablesfor atestcase_stepentry that does not exist → oneE_WARNINGper test case. The BFF passes the sameexclude_children_of => testcasefilter thattestsuite::get_subtree()uses, so a 210-case run is warning free (core bug filed as #1589). - Statuses, messages and notes keep the legacy wording so existing automation servers (and existing documentation) need no change.
| Issue | Symptom | Fix |
|---|---|---|
| #1588 |
lib/functions/remote_exec.php:125 looked the result code up in $code_status unguarded → PHP 8 E_WARNING "Undefined array key" for every non-conformant XML-RPC answer, plus a null label |
guarded lookup; the code is still displayed verbatim (e12b249d7) |
| (in #1587) | only passed / failed were compared, so a b (blocked) answer was counted as passed |
taeResolveResultStatus() maps every code through code_status; counters and badges use it |
| #1589 |
tree::_get_subtree() walks into testcase_step children → one E_WARNING per test case in the Event Viewer |
contained in the BFF (init and run) with the exclude_children_of => testcase filter; core fix still open |
Found by the code review of the change set:
| Finding | Fix |
|---|---|
IXR_Client built without a timeout → a hung automation server blocks the request for the OS default |
20s per remote call, surfaces as CONNECTION FAILURE
|
| plan / build / platform ids of the XML-RPC context were not checked against the authorised project |
taeOwnsPlan() / taeOwnsBuild() / taeOwnsPlatform() drop foreign ids |
a non-array (or result-less) XML-RPC answer made the legacy controller read an array offset on a non-array |
answer validated, reported as a config problem |
the result badge printed a raw i18n key for the x / a result codes |
tae.status_not_available / tae.status_all added to the 10 bundles + fallback to the raw code |
the "Open test case" fallback pointed at the non-existing testcases/searchTestCase.html
|
now search/searchView.html
|
re-running the fixture reset the shared norights user and could delete the automation custom fields of a foreign project |
only creates the user when missing, skips fields linked to another project |
-
tae.*— 53 keys (titles, cards, context, target, counters, statuses, buttons, states, truncation bar) in all 10 client bundles (en,ro,de,es,fr,it,pt,ru,ja,zh). -
tae.answered/tae.configProblems/tae.connectionFailure— the execution status column. -
tae.status_passed/tae.status_failed/tae.status_blocked/tae.status_not_run/tae.status_not_available/tae.status_unknown/tae.status_all— the result column, one key perresults.status_codedomain ofcfg/const.inc.php. A code the page does not know falls back to the raw code the automation server sent (never a raw i18n key). -
footers.tcAutoExec— footer line. -
href_tc_auto_exec— ASIDE label, added to all 19locale/*/strings.txt.
No hardcoded strings on the page; the TLi18n locale switcher works like on every modern screen.
- Session-based auth (401 for anonymous), rights fail-closed on the owning project.
-
bffSameOriginGuard()CSRF proof required for the POST (403). - The testplan API key never leaves the server.
- All ids are cast to
int, all SQL uses the framework database class; node ownership is verified before the run.
Suite 1587 in tmp/TLU_Test_Cases.md — 24/24 PASS: the three levels,
the custom-field cascade, pass / fail / config-problem / connection-failure
rendering, the 200-case truncation bar, plan → build/platform re-init, the
400/401/403/404/405 + CSRF contract, unknown project, login redirect, the
access-denied state, the ASIDE entries, the legacy shim, the ro locale, the
i18n coverage, the #1588 and #1589 regressions, Event Viewer hygiene (0 new
Error/Warning) and the lint/diff checks.
Fixtures: tmp/fixtures_1587.php (project 107, two plans, build 13, two
platforms, three suites, three test cases, the six automation custom fields,
the role-less norights user) and tmp/fixtures_1587_bulk.php (a 210-test-case
suite for the truncation test). The XML-RPC double used for the runs is a
throwaway script outside the repository.