Skip to content

test(integration): verify script ordering against compatible Coder versions - #552

Merged
BobbyHo merged 8 commits into
mainfrom
bobby/plat-553-verify-script-ordering-integration
Oct 20, 2026
Merged

BobbyHo merged 8 commits into
mainfrom
bobby/plat-553-verify-script-ordering-integration

Conversation

@BobbyHo

@BobbyHo BobbyHo commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

TL;DR

The provider and Coder each test their half of coder_script_order on their own, but nothing runs them together, so a renamed field on either side would pass every test and silently stop ordering scripts. This PR adds integration cases that push templates using coder_script_order to a real Coder image, start a workspace agent inside the Coder container, and check that scripts ran in the declared order. On Coder images older than the feature the ordering cases skip with a message naming both versions, and one case proves such templates still build there.

Refs https://linear.app/codercom/issue/PLAT-553/phase-4-verify-script-ordering-against-compatible-coder-versions

How to navigate this PR
  • Everything here is test code and test templates. There is no change under provider/. About 360 lines of Go, five Terraform templates and four README sentences.
  • Reading order:
    1. integration/integration_test.go: one optional verify field on the case table and one guarded call after assertOutput. Then the five new table entries at the end of the table. Nothing else in the harness changes.
    2. integration/agent_test.go, the decode structs at the top: the few API fields the cases read. The package does not import codersdk, for the same reason the harness never has.
    3. integration/agent_test.go, the helpers: startAgent, stopAgent, apiGet, agentIDFor, waitForAgent, then the small readers and matchers. agentIDFor is the one to pause on, see Implementation.
    4. integration/coder-script-order/main.tf: the ordered template. The other four templates are variations of it.
    5. integration/agent_test.go, the four verify* functions: one per agent case. Each starts the agent, waits, then reads the durable file, the build timings and the stored dependencies.
    6. README.md: how to run these locally.
  • The most important function is verifyScriptOrder, and inside it the requireDependencies calls. That is the cross-repository contract check: if either repository renames a field in the plan JSON, those four calls fail with the script name and the missing dependency.
Implementation
  • integration/integration_test.go
    • Adds an optional verify function to the case struct, called after assertOutput with the decoded output. Existing cases leave it nil.
    • Adds five cases. Four are gated with minVersion: "v2.39.0", the first release that enforces ordering. The compat case uses v0.0.0 so it runs on every image.
  • integration/agent_test.go
    • startAgent runs coder agent in the background inside the Coder container. The agent reads its token through CODER_AGENT_TOKEN_FILE, so the token never appears in the command the harness logs. The command execs the agent in a subshell so the PID file holds the agent's own PID. Each case gets its own log and data directories because the cases run in parallel in one container.
    • stopAgent sends SIGTERM to that PID. It never signals by process name, because the server in the same container is the same binary.
    • apiGet calls the API through curl in the container as the workspace owner and reports the HTTP status and body on failure. The session token is substituted by the container's shell at the moment of the call.
    • agentIDFor reads the agent ID from the workspace's latest build. The coder_agent resource's id in Terraform is not the ID coderd stores: coderd generates its own on insert. The first run of these tests got a 404 on the Terraform ID, which is why this helper exists.
    • waitForAgent polls the agent's lifecycle state with a two-minute limit and prints the agent log tail on timeout, so a failure to connect reads differently from a failure to order.
    • requireLineAfter checks relative order only. Scripts that start together may write to the file in either order.
  • Templates
    • coder-script-order: four startup scripts and two rules. clone_repo sleeps three seconds so the unordered script has time to start before it ends. Every script appends a start line and an end line to one file per case.
    • coder-script-order-skip: the same with clone_repo exiting 1.
    • coder-script-order-stop: one startup script so the agent reaches ready, two stop scripts and a stop rule.
    • coder-script-order-cancel: the same as the ordered template with clone_repo sleeping sixty seconds.
    • coder-script-order-compat: the smallest template that uses the data source. It writes the agent ID into its output file on purpose. Coder drops an agent that no resource references, and the build then fails with "agent_id does not match any workspace agent or devcontainer subagent". The other templates reference the agent through their token files.
    • The agent token and the owner session token go to local_sensitive_file resources, not into the JSON output, so they stay out of the test log. The existing workspace-owner case puts its session token in the JSON; that case is not changed here.
  • README.md: four sentences. On macOS the provider must be built for Linux first, because the binary runs inside the container. The other three say what the new cases do and when they skip.
  • Not done on purpose: no gate on the server's reported version. The harness's minVersion is what every existing case uses, and latest bypasses it so the preview row fails, rather than skips, when coder/coder main breaks the contract.
Expected Output
  • On coder-preview:latest, with four startup scripts and rules that put install_tools and post_setup after clone_repo, the durable file shows both dependents starting after clone_repo ends, and start_code_server, which no rule names, starting before it ends. The build timings show the same order by timestamp, every status ok.
  • The agent's scripts, read through the API, carry exactly the dependencies the template declared: install_tools on coder_script.clone_repo with requirement success, post_setup on the same with completion, the other two none.
  • When clone_repo exits 1, install_tools never runs, its timing is skipped with equal start and end, its log carries Skipping script: dependency "Clone repo" failed., post_setup still runs because its rule asks for completion, and the agent ends in start_error.
  • When the agent receives SIGTERM after it is ready, stop_db starts only after save_state ends, and the build timings carry both stop-stage entries as ok.
  • When the agent receives SIGTERM while clone_repo is still running, clone_repo is canceled with a positive interval, install_tools and post_setup are canceled with zero-length timings, start_code_server is ok, and the logs carry Canceled before starting. and Canceled while running. on the right scripts.
  • On a Coder image older than v2.39.0, each of the four agent cases prints skipping due to CODER_VERSION "v2.38.0" < minVersion "v2.39.0" and the step stays green.
  • On every image, a template that uses coder_script_order still imports and builds. On an older image the provisioner ignores the data source; on a newer one it stores the dependency. The compat case passes in both.
  • No agent token or session token appears in the test log.
Testing
  • integration/integration_test.go, TestIntegration: five new subtests.
    • coder-script-order checks the first two bullets of Expected Output.
    • coder-script-order-skip checks the skip bullet.
    • coder-script-order-stop checks the stop bullet.
    • coder-script-order-cancel checks the cancel bullet.
    • coder-script-order-compat checks the last-but-one bullet and, through the harness's version gate, the skip-message bullet is what the other four produce on older images.
  • The token bullet is covered by construction rather than by an assertion: the tokens are never in the output JSON or in a logged command, and the run logs below show none.
  • Ran with Docker on an Apple silicon Mac, provider built with GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build .:
    • CODER_IMAGE=ghcr.io/coder/coder-preview CODER_VERSION=latest go test -count=1 -v ./integration/: all five new cases pass. Four pre-existing cases fail on this host only, because they compare provisioner.os against the test host's OS (darwin) while the provisioner in the container reports linux. They pass on the Linux CI runner and are not touched by this PR.
    • CODER_IMAGE=ghcr.io/coder/coder CODER_VERSION=v2.38.0 go test -count=1 -v -run 'TestIntegration/coder-script-order' ./integration/: four skips, compat passes.
  • gofmt, go vet ./integration, terraform fmt -check -recursive integration/ all clean. Each new template passes terraform validate against the locally built provider through a dev_overrides terraformrc.
Manual Test

Docker Desktop 29.5.3 on an Apple silicon Mac. Preview image v2.38.0-devel+200fa7dea7 (built 2026-10-19 17:15 UTC). Release image ghcr.io/coder/coder:v2.38.0.

# Scenario Result
1 Whole package against coder-preview:latest Pass for all five new cases. Four pre-existing cases fail on macOS only, see Testing
2 The five cases against coder:v2.38.0 Pass: four skips, compat passes
1. Whole package against coder-preview:latest
CODER_IMAGE=ghcr.io/coder/coder-preview CODER_VERSION=latest TIMEOUT_MINS=15 go test -count=1 -v ./integration/
    --- PASS: TestIntegration/coder-ai-task (10.14s)
    --- PASS: TestIntegration/coder-app-open-in (10.74s)
    --- FAIL: TestIntegration/workspace-owner-filled (11.10s)      Expect "linux" to match "darwin" (provisioner.os, macOS host only)
    --- FAIL: TestIntegration/workspace-owner-rbac-roles (11.22s)  same
    --- PASS: TestIntegration/coder-script-order-skip (11.32s)
    --- FAIL: TestIntegration/test-data-source (11.79s)            same
    --- PASS: TestIntegration/coder-app-hidden (12.22s)
    --- FAIL: TestIntegration/workspace-owner (12.40s)             same
    --- PASS: TestIntegration/coder-script-order-compat (12.81s)
    --- PASS: TestIntegration/coder-script-order (12.91s)
    --- PASS: TestIntegration/coder-script-order-cancel (6.93s)
    --- PASS: TestIntegration/coder-script-order-stop (8.56s)
2. The five cases against coder:v2.38.0
CODER_IMAGE=ghcr.io/coder/coder CODER_VERSION=v2.38.0 TIMEOUT_MINS=15 go test -count=1 -v -run 'TestIntegration/coder-script-order' ./integration/
    integration_test.go:293: skipping due to CODER_VERSION "v2.38.0" < minVersion "v2.39.0"
    integration_test.go:293: skipping due to CODER_VERSION "v2.38.0" < minVersion "v2.39.0"
    integration_test.go:293: skipping due to CODER_VERSION "v2.38.0" < minVersion "v2.39.0"
    integration_test.go:293: skipping due to CODER_VERSION "v2.38.0" < minVersion "v2.39.0"
    --- SKIP: TestIntegration/coder-script-order-stop (0.00s)
    --- SKIP: TestIntegration/coder-script-order-cancel (0.00s)
    --- SKIP: TestIntegration/coder-script-order-skip (0.00s)
    --- SKIP: TestIntegration/coder-script-order (0.00s)
    --- PASS: TestIntegration/coder-script-order-compat (3.88s)
ok  	github.com/coder/terraform-provider-coder/v2/integration	10.673s

…rsions

Add five cases that push templates using coder_script_order to a real
Coder image. Four start a workspace agent inside the container and check,
from a durable file and the build timings API, that startup scripts run
in order, a dependent of a failed script is skipped, stop scripts run in
order, and cancellation reports canceled outcomes. They also check that
the stored dependencies match the template, so a renamed field on either
side fails CI. The fifth proves an older Coder still builds the template.

The agent cases are gated at v2.39.0 and skip on older images.

The tests read the agent ID from the workspace because coderd generates
its own on insert, and the compat template writes the agent ID to its
output because Coder drops an agent that no resource references.
@linear-code

linear-code Bot commented Oct 19, 2026

Copy link
Copy Markdown

PLAT-553

@BobbyHo

BobbyHo commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

/coder-agents-review Please limit the review to P0, P1, and P2 issues only.

@coder-agents-review

coder-agents-review Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Chat: Review posted | View chat
Requested: 2026-10-20 00:09 UTC by @BobbyHo

Review history
  • R1 (2026-10-19): 12 reviewers, 7 Nit, 2 P2, 7 P3, 14 P4, COMMENT. Review
  • R2 (2026-10-20), 7 Nit, 2 P2, 7 P3, 14 P4, COMMENT. Review

deep-review v0.13.0 | Round 2 | e851c57..e7fd688

Last posted: Round 2, 30 findings (2 P2, 7 P3, 14 P4, 7 Nit), COMMENT. Review

Finding inventory

Finding inventory, PR #552

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P3 Open README.md:88 README says cases skip on old images; gate compares CODER_VERSION string, so non-semver/prerelease tags skip too R1 Netero Yes
CRF-2 P4 Open integration/agent_test.go:345 Cancel case never asserts the final lifecycle state R1 Netero Yes
CRF-3 Nit Open integration/agent_test.go:7 stdlib slices vs golang.org/x/exp/slices in the same package R1 Netero Yes
CRF-4 P2 Author fixed (6e63995) integration/agent_test.go:263 Timings and script logs read once after lifecycle change; agent reports lifecycle before they are stored R1 Komugi P2, Takumi P2, Melody P3, Bisky P3 Yes
CRF-5 P2 Author fixed (e7fd688) integration/agent_test.go:340 Cancel case SIGTERMs before start_code_server is guaranteed done, then requires it ok R1 Komugi P3, Takumi P3, Bisky P3 Yes
CRF-6 P3 Open integration/agent_test.go:251 Case name repeated in table, const name, and template /tmp literals R1 Ryosuke P3, Gon P4 Yes
CRF-7 P4 Open integration/integration_test.go:233 minVersion v2.39.0 is an anticipated release, repeated four times without a shared constant R1 Ryosuke, Gon Yes
CRF-8 P3 Open integration/coder-script-order/main.tf:88 agent.id output is the Terraform ID the API does not know; no verify reads it R1 Gon P3, Ryosuke Note, Leorio Note Yes
CRF-9 P4 Open integration/agent_test.go:341 require inside Eventually condition calls FailNow from testify goroutine, waits full timeout R1 Takumi Yes
CRF-10 P3 Open integration/integration_test.go:265 Cancel case and skip log-text assertion couple provider CI to Coder agent wording R1 Pariston Yes
CRF-11 Note Note (body) integration/coder-script-order-stop/main.tf:62 Stop case is the only coverage of phase = "stop" R1 Pariston No
CRF-12 P3 Open integration/coder-script-order-stop/main.tf:25 Comment says warm script is needed to reach ready; agent reaches ready without it R1 Gon Yes
CRF-13 Nit Open integration/integration_test.go:71 verify field comment carries usage advice R1 Gon P2 Yes
CRF-14 Nit Open integration/integration_test.go:276 Compat comment first sentence repeats minVersion v0.0.0 R1 Gon P2 Yes
CRF-15 P4 Open integration/agent_test.go:74 stopAgent doc states a purpose the cancel caller does not have R1 Gon P2 Yes
CRF-16 Nit Author fixed (6e63995) integration/agent_test.go:187 latestBuildTimings doc repeats the signature R1 Gon P2 Yes
CRF-17 Nit Open integration/agent_test.go:214 scriptFor doc repeats signature, omits that it fails the test R1 Gon P2 Yes
CRF-18 P4 Open integration/agent_test.go:236 "agent log" names both the agent stdout file and API script logs R1 Gon Yes
CRF-19 P4 Open integration/agent_test.go:17 Decode struct names drop parts of the codersdk names they mirror R1 Gon Yes
CRF-20 P4 Open integration/agent_test.go:275 3*time.Second duplicates template sleep 3 with no link R1 Gon Yes
CRF-21 P4 Open integration/coder-script-order-skip/main.tf:30 timeout = 30 copied onto a script that exits immediately R1 Gon Yes
CRF-22 Nit Open integration/agent_test.go:155 "durable file" is a second name for order_log R1 Gon Yes
CRF-23 P3 Open integration/agent_test.go:255 Wrong terminal lifecycle state fails without agent log or timings R1 Leorio P3, Chopper P3 Yes
CRF-24 P4 Open integration/agent_test.go:298 Status and exit-code assertions carry no message naming the script R1 Leorio P4, Chopper Nit Yes
CRF-25 P4 Open integration/coder-script-order-compat/main.tf:44 Comment says no resource references the agent, but coder_script does R1 Leorio Yes
CRF-26 P4 Open README.md:88 coder-script-order* skip sentence includes the compat case, which always runs R1 Leorio Yes
CRF-27 P4 Open README.md:85 macOS Linux-build instruction comes after the make step it must precede R1 Leorio Yes
CRF-28 Nit Open integration/integration_test.go:1 Commit subject is 75 characters R1 Leorio Yes
CRF-29 P3 Open integration/agent_test.go:259 On a dependency-field rename the order check fails before requireDependencies can name the cause R1 Chopper Yes
CRF-30 P4 Open integration/agent_test.go:343 Cancel case agent connect failure reads as "clone_repo never started" with no log tail R1 Chopper Yes
CRF-31 P4 Open integration/coder-script-order/main.tf:33 code-server-before-clone-end assertion relies only on sleep 3 R1 Komugi Yes
CRF-32 Note Note (body) integration/agent_test.go:143 Each poll logs the full agent JSON through execContainer R1 Chopper No
CRF-33 OOS Out of scope (body) .github/workflows/test.yml:5 devel row runs only on provider PRs and pushes, so a Coder-side rename is caught only on the next unrelated provider PR R1 Pariston P2 No
CRF-34 OOS Out of scope (body) integration/integration_test.go:292 minVersion gate treats non-semver and prerelease tags as older than every minVersion R1 Netero No
CRF-35 OOS Out of scope (body) integration/integration_test.go:302 Non-semver tags select deprecated templates create R1 Netero No
CRF-36 OOS Out of scope (body) integration/workspace-owner/main.tf Session token written to output JSON and logged by execContainer R1 Netero, Chopper No
CRF-37 OOS Out of scope (body) coder/coder agent/agent.go:2275 Agent reports final lifecycle before script timings and logs are flushed R1 Takumi, Bisky No
CRF-38 OOS Out of scope (body) integration/integration_test.go:425 setup Eventually condition calls require through execContainer R1 Takumi No
CRF-39 OOS Out of scope (body) integration/integration_test.go:373 Container PID 1 (coder server) does not reap exited agents and script children R1 Takumi No

Contested and acknowledged

Round log

Round 1

Netero first pass: 1 P3, 1 P4, 1 Nit. No P0, panel proceeds.
Round type: round 1, full panel. Multi-domain (Go test harness plus token handling through shell commands), target 9-12. Specialists: ging-go, ryosuke (Go), takumi (agent process start/SIGTERM shutdown), kurapika (agent and session tokens), melody (API JSON decode structs mirroring Coder). Core: pariston, mafuuu. Pool: bisky (tests), komugi (timing-dependent tests), gon, leorio (floor). Wildcard (random from distilled set): chopper. 12 panel reviewers.
Panel: ging-go, kurapika, mafuuu no findings. Cross-check: CRF-4 convergent across four reviewers, set at P2 (higher wins); orchestrator confirmed agent/agent.go:2275/2277/2360 ordering on coder/coder main 200fa7dea7. Komugi's PID-exit fix rejected in favor of polling: Takumi showed PID 1 does not reap the agent, so kill -0 succeeds on the zombie. CRF-5 raised from P3 to P2: same consequence as CRF-4 (intermittent red devel row on unrelated PRs) with an induced-delay reproduction. Gon's comment-wording P2s downgraded: keep-argument is that the rubric rates bloat P2 and the stopAgent text misstates a caller; drop reason is that none changes behavior or misleads about a failure, so Nit (CRF-13,14,16,17) and P4 (CRF-15). Pariston's scheduled-run P2 moved out of scope: the fix is in test.yml, which the PR does not change. A PR comment from the requester asks to limit the review to P0 to P2. deep-review post rejects unposted Open findings, so all in-scope findings are posted and the body names the two inside that limit. Reviewed against e851c57..026b8a8.

Round 2 update

BLOCKED. Churn guard: 3 addressed (CRF-4 in 6e63995, CRF-5 in e7fd688, CRF-16 by the 6e63995 rewrite), 27 silent. The requester posted "Please limit the review to P0, P1, and P2 issues only." a second time; churn guard classified it as a scope request, not a response to any finding. No reviewers, no Netero. Reviewed against 026b8a8..e7fd688.

About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Komugi flake/determinism
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds five integration cases that run coder_script_order templates against a real Coder image with an agent started in the container. 2 P2, 7 P3, 14 P4 and 7 Nit findings. The PR comment asked for P0 to P2 only: the two P2 findings, both intermittent failures in the new cases, are the ones inside that limit, and the rest are lower severity.

Out of scope (needs a ticket or explicit acceptance by a human):

  • .github/workflows/test.yml:5: the devel row, the only row that runs these cases today, has no schedule trigger, so a Coder main rename of a dependency field is detected only on the next provider PR, whose author did not cause it.
  • integration/integration_test.go:292: the minVersion gate treats main-... and prerelease tags as older than every minVersion, so all gated cases skip on pinned preview images.
  • integration/integration_test.go:302: the same tags select the deprecated coder templates create.
  • integration/workspace-owner/main.tf: the session token is written to the output JSON, which execContainer logs, so it is in CI logs.
  • coder/coder agent/agent.go:2275: the agent reports its final lifecycle state before script timings and logs are flushed, so API clients cannot treat ready, start_error or off as "results stored".
  • integration/integration_test.go:425: setup's require.Eventually condition calls require through execContainer, so a Docker error waits the full 12 s.
  • integration/integration_test.go:373: PID 1 in the Coder container is coder server, which does not reap exited agents or script children; they stay zombies until the container is removed.

Notes:

  • coder-script-order-stop is the only case that exercises phase = "stop".
  • Each waitForAgent poll logs the full agent JSON through execContainer, so a timeout produces about 120 copies before the failure line.

integration/integration_test.go:1

Nit [CRF-28] The commit subject is 75 characters, 82 after the squash suffix (#552). (Leorio)

Keep it under 72, for example test(integration): run coder_script_order cases against a real Coder.

🤖

🤖 This review was automatically generated with Coder Agents.

Comment thread integration/agent_test.go Outdated
Comment thread integration/agent_test.go Outdated
Comment thread README.md Outdated
Comment thread integration/agent_test.go Outdated
Comment thread integration/agent_test.go
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread integration/agent_test.go Outdated
Comment thread integration/agent_test.go Outdated
Comment thread integration/coder-script-order/main.tf
The agent reports ready or off before the goroutines that send script
timings and logs have finished, so a single read right after the state
change can come back empty.
code-server starts in parallel with clone_repo, so a signal sent as soon
as clone_repo has started can also cancel code-server and fail the ok
assertion on its timing.
@BobbyHo

BobbyHo commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

/coder-agents-review Please limit the review to P0, P1, and P2 issues only.

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The author reports that commits 6e63995 and e7fd688 fix the two P2 findings (timings and logs read before the agent stores them, and the cancel case signaling before code-server exits). Review panels will check those fixes in the next round.

This round has no review. 27 findings from the previous round have no reply on their threads and no change in the code. The request to limit the review to P0 to P2 does not say what happens to each of these findings. For each one, do one of these: fix it in this PR, link a GitHub issue, or reply on the thread with why it should stay as it is. A human can also reply that they accept every P3, P4 and Nit finding below as not fixed in this PR. The next round starts after one of these happens.

Findings that need a response:

  • P3 README.md:88: README says the cases skip on old images; the gate compares the CODER_VERSION string
  • P3 integration/agent_test.go:251: case name repeated in the table, const name, and template /tmp paths
  • P3 integration/coder-script-order/main.tf:88: agent.id output is the Terraform ID the API does not know
  • P3 integration/integration_test.go:265: cancel case and log-text assertions tie provider CI to Coder agent wording
  • P3 integration/coder-script-order-stop/main.tf:25: comment says warm is needed to reach ready
  • P3 integration/agent_test.go:255: wrong terminal lifecycle state fails without the agent log or timings
  • P3 integration/agent_test.go:259: a dependency-field rename fails the order check before requireDependencies names the cause
  • P4 integration/agent_test.go:345: cancel case never asserts the final lifecycle state
  • P4 integration/integration_test.go:233: v2.39.0 repeated without a shared constant
  • P4 integration/agent_test.go:341: require inside the Eventually condition waits the full timeout on a Docker error
  • P4 integration/agent_test.go:74: stopAgent doc states a purpose the cancel caller does not have
  • P4 integration/agent_test.go:236: "agent log" names two different things
  • P4 integration/agent_test.go:17: decode struct names drop parts of the codersdk names
  • P4 integration/agent_test.go:275: 3*time.Second duplicates the template's sleep 3
  • P4 integration/coder-script-order-skip/main.tf:30: timeout = 30 on a script that exits at once
  • P4 integration/agent_test.go:298: status assertions carry no message naming the script
  • P4 integration/coder-script-order-compat/main.tf:44: comment contradicts the coder_script references in the file
  • P4 README.md:88: skip sentence includes the compat case
  • P4 README.md:85: macOS build instruction comes after the make step
  • P4 integration/agent_test.go:343: agent connect failure reads as a script failure with no log tail
  • P4 integration/coder-script-order/main.tf:33: code-server-before-clone-end assertion relies only on sleep 3
  • Nit integration/agent_test.go:7: stdlib slices vs golang.org/x/exp/slices
  • Nit integration/integration_test.go:71: verify field comment carries usage advice
  • Nit integration/integration_test.go:276: compat comment repeats minVersion
  • Nit integration/agent_test.go:214: scriptFor doc omits that it fails the test
  • Nit integration/agent_test.go:155: "durable file" is a second name for the order log
  • Nit integration/integration_test.go:1: commit subject is 75 characters

🤖 This review was automatically generated with Coder Agents.

@BobbyHo
BobbyHo requested a review from geokat October 20, 2026 01:20
Check dependencies before order, print the agent log tail on a wrong
lifecycle state, and add the script name to status assertions. The
checks on Coder's skip and cancel log wording are removed so a wording
change on Coder main cannot fail provider CI.
… values

Templates name their files after var.output_path so a copied template
cannot share one. clone_repo waits for the unordered script instead of
a sleep. Unused agent.id output, warm script, timeout and x/exp import
removed.
@BobbyHo
BobbyHo marked this pull request as ready for review October 20, 2026 14:59

@geokat geokat left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - great stuff 👍

I left just a nit and here's a couple of edge cases an agent found (up to you if you want to fix them or not).

  1. Cancellation test can race with code-server finishing — agent_test.go:396. Seeing start_code_server end proves the last echo ran, but the agent may not have collected the process’s exit yet. SIGTERM can then produce a "canceled" timing, failing the later "ok" assertion. Wait for code-server’s successful timing before signaling.

  2. A polling callback still indirectly calls require.NoError(t, ...) — agent_test.go:245. apiGet calls execContainer, which uses require on the original t. A Docker error therefore terminates the callback goroutine. In this Testify version, EventuallyWithT can interpret the untouched collector as success and return prematurely. The test remains failed, but polling stops and subsequent assertions see empty timings. Have apiGet use tryExecContainer and return its error.

Comment thread integration/agent_test.go
agent_test.go keeps the helpers any case with a live agent can reuse:
starting and stopping the agent, reading the API, waiting for a
lifecycle state and reading build timings. script_order_test.go holds
the order log helpers, the dependency assertion and the four verify
functions, which only make sense for the script ordering templates.
No code changed, only its location.
apiGet now returns a Docker error instead of calling require. It is
polled from testify's goroutine in waitForTimings, where a failed
require ends the poll early and leaves the test to fail later on
empty timings.

The cancel case waits for the code-server start timing before sending
the signal. The order log only shows the script's last line ran; the
timing shows the agent saw the process exit and marked it ok, so the
signal cannot cancel it as well.
@BobbyHo

BobbyHo commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the two edge cases! Both fixed in 44a754a: apiGet now returns the Docker error instead of calling require, and the cancel case waits for the code-server start timing before sending the signal.

@BobbyHo
BobbyHo merged commit d5137fb into main Oct 20, 2026
3 checks passed
@BobbyHo
BobbyHo deleted the bobby/plat-553-verify-script-ordering-integration branch October 20, 2026 20:46
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 20, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants