test: D1-8 enforce MacroTimeout, macro times out within wall-clock budget
This commit is contained in:
@@ -121,7 +121,7 @@ All reconciled to follow code. Specs must be self-consistent and match code.
|
||||
| D1-5 | ~~LiquidTagSubset (5 tags only)~~ | template.allium:179 | **Resolved:** added `BDS.Rendering.LiquidParser`, a restricted Liquex parser recognizing only the subset (if/for/assign/render + `{{ }}` output); any other tag (`unless`, `case`, `capture`, `tablerow`, `cycle`, `increment`, …) leaves unmatched input and fails `eos/0`. Wired into `validate_liquid` (publish gate), `template_selection.render_template`, `filters.render_macro_source`, and MCP `validate_template` so validation and rendering share the same surface; 6 parametrized tests added asserting unsupported tags are rejected at publish |
|
||||
| D1-6 | ~~LiquidFilterSubset (4 standard + 2 custom)~~ | template.allium:191 | **Resolved:** added `LiquidParser.validate/1`, which parses with the restricted tag grammar then walks the AST to reject any filter outside the allowed set — 4 standard (`escape`, `url_encode`, `default`, `append`) + 3 custom (`i18n`, `markdown`, `slugify`). Wired into `validate_liquid` (publish gate) and MCP `validate_template` so unsupported filters are rejected even though Liquex would otherwise apply them as built-in standard filters. Spec corrected to 3 custom filters (bundled templates use `slugify`); 9 tests added (6 unsupported filters rejected, 3 supported filters accepted). |
|
||||
| D1-7 | ~~LiquidOperatorSubset~~ | template.allium:210 | **Resolved:** `LiquidParser.validate/1` now walks the parsed AST for `{:op, _}` nodes and rejects any comparison operator outside the allowed `==`/`>` subset (`!=`, `<`, `>=`, `<=`, `contains`), sharing the publish gate and MCP `validate_template` surface with the tag/filter checks; spec `LiquidOperatorSubset` annotated with enforcement note; 10 tests added (5 unsupported operators rejected at publish, 5 supported `==`/`>`/`and`/`or`/bare-truthy expressions accepted). |
|
||||
| D1-8 | MacroTimeout guarantee | script.allium:94-95 | Write test: macro times out within budget |
|
||||
| D1-8 | ~~MacroTimeout guarantee~~ | script.allium:94-95 | **Resolved:** added test in `api_test.exs` — an infinite-loop `render()` macro run with `max_reductions: :none` (forces the luerl sandbox onto its wall-clock path) and a 150ms `timeout` returns `{:error, :timeout}` and terminates within budget (<2s), proving the macro is killed near its budget rather than the default multi-minute script timeout |
|
||||
| D1-9 | ExecuteTransform rule (pipeline, ordering, toast budget) | script.allium:229-263 | Write test: transform pipeline executes in order, toast budget enforced |
|
||||
| D1-10 | TransformPipelineContinuation | script.allium:247-249 | Write test: error in transform doesn't halt pipeline |
|
||||
| D1-11 | ChatContextTruncation invariant | ai.allium:375-379 | Write test: long chat history trimmed to context window |
|
||||
|
||||
@@ -109,6 +109,33 @@ defmodule BDS.Scripting.ApiTest do
|
||||
assert {:error, _reason} = BDS.Scripting.execute_macro(project.id, bad_source, [])
|
||||
end
|
||||
|
||||
test "macro execution is bounded by its timeout budget (MacroTimeout)", %{project: project} do
|
||||
# An entrypoint that never returns must not run forever: the macro timeout
|
||||
# budget terminates it and degrades to an error. max_reductions: :none forces
|
||||
# the luerl sandbox onto its wall-clock path so we exercise the time budget
|
||||
# itself rather than the reduction limit.
|
||||
looping_source = "function render() while true do end end"
|
||||
budget_ms = 150
|
||||
|
||||
{elapsed_us, result} =
|
||||
:timer.tc(fn ->
|
||||
BDS.Scripting.execute_macro(project.id, looping_source, [],
|
||||
timeout: budget_ms,
|
||||
max_reductions: :none
|
||||
)
|
||||
end)
|
||||
|
||||
assert {:error, :timeout} = result
|
||||
|
||||
elapsed_ms = div(elapsed_us, 1000)
|
||||
|
||||
# The macro must be killed close to its budget, never allowed to run for the
|
||||
# default multi-minute script timeout. Generous upper bound to stay stable
|
||||
# on loaded CI while still proving the budget is enforced.
|
||||
assert elapsed_ms < 2_000,
|
||||
"macro ran for #{elapsed_ms}ms, expected termination near the #{budget_ms}ms budget"
|
||||
end
|
||||
|
||||
test "project scripting exposes project, post, script, template, metadata, and task namespaces",
|
||||
%{
|
||||
project: project
|
||||
|
||||
Reference in New Issue
Block a user