test(e2e): speed up and cover exec and Kubernetes modes (#1363)

Follow-up to https://gitea.com/gitea/runner/pulls/1362, whose crash e2e missed because it only drove the daemon on Docker.

- `dispatch`, `failure_paths` and `reusable_workflow` run through the daemon and `exec`, each on Docker and one shared k3s cluster.
- Fixed sleeps become gates the test releases, the job timeout uses a 15s runner deadline, k3s boots alongside Gitea, Gitea's data is on tmpfs.
- Outside a container, `make test-e2e` runs `go test` in a Linux container on its own network like CI, so local runs take the same paths.

Local wall time:

| | Before | After |
|---|---|---|
| Suite | 84s | 27–35s |
| `job_timeout` | 64s | 17s |
| `reconnect` | 22s | 4.5s |
| `capacity/serial` | 20s | 2s |
| `cli_shutdown_drains` | 14s | 2.3s |
| `kubernetes` | 31s | 21–23s |

_Written by Claude (Opus 5.5)._

---------

Co-authored-by: bircni <[email protected]>
Reviewed-on: https://gitea.com/gitea/runner/pulls/1363
Reviewed-by: bircni <[email protected]>
Co-authored-by: silverwind <[email protected]>
This commit is contained in:
silverwindandbircni authored and bircni committed 2026-10-31 10:47:35 +00:00
1 parent 2e72cf902a
commit a46d3f3eda
23 files changed
+577 -340

No files matched your search

+11 -10
View File
@@ -28,7 +28,7 @@ func testRunCancellation(t *testing.T) {
pushWorkflow(t, api, repo, "cancel.yml")
wfRun := waitForRun(t, api, repo)
waitForRunningJobLog(t, api, repo, wfRun.ID, "e2e-live-log-marker")
waitForRunningJobLog(t, api, repo, wfRun.ID, "e2e-live-log-marker", 1)
if !cancelSupported {
requireSuccess(t, api, repo, wfRun.ID)
return
@@ -49,31 +49,32 @@ func testRunCancellation(t *testing.T) {
}
}
func waitForRunningJobLog(t *testing.T, api *GiteaAPI, repo string, runID int64, substr string) {
func waitForRunningJobLog(t *testing.T, api *GiteaAPI, repo string, runID int64, prefix string, count int) {
t.Helper()
// The budget covers scheduling and the container start, which a loaded runner makes slow.
ctx, cancel := context.WithTimeout(t.Context(), runTimeout)
defer cancel()
status := "none"
for {
jobs, err := api.Jobs(ctx, repo, runID)
if err != nil {
t.Fatalf("list jobs: %v", err)
}
if len(jobs) > 0 {
status = jobs[0].Status
if status == "in_progress" {
logs, err := api.JobLogs(ctx, repo, jobs[0].ID)
if err == nil && commandRow(logs, substr) == substr {
return
logged := 0
for _, job := range jobs {
if job.Status == "in_progress" {
if logs, err := api.JobLogs(ctx, repo, job.ID); err == nil && commandRow(logs, prefix) != "" {
logged++
}
}
}
if logged >= count {
return
}
select {
case <-ctx.Done():
dumpRunLogs(t, api, repo, runID)
t.Fatalf("job of run %d is %q and never logged %q", runID, status, substr)
t.Fatalf("%d of %d running jobs of run %d logged %q", logged, count, runID, prefix)
case <-time.After(pollInterval):
}
}