mirror of
https://gitea.com/gitea/act_runner
synced 2026-09-21 19:37:07 +02:00
test: add end-to-end Gitea compatibility suite (#1180)
Adds a real-Gitea compatibility suite against stable and nightly to catch runner and API drift before release. The suite shares one Gitea and regular runner, using repository runners only for cache v1/v2 and ephemeral behavior. It covers registration, payload and log encoding, secrets, variables, services, artifacts, outputs, matrices, cache, dispatch, live logs, cancellation, and ephemeral teardown. CI runs both images in parallel. Warm local timings: | Image | Before | After | | --- | ---: | ---: | | `gitea/gitea:latest` | ~70s | 26.54s | | `gitea/gitea:main-nightly` | ~54s | 22.53s | The former serial matrix took about 2 minutes. Parallel suite execution is now bounded by the slower ~26.5-second variant. Shared Renovate matcher: https://gitea.com/gitea/renovate-config/pulls/552 --------- Co-authored-by: silverwind <me@silverwind.io> Reviewed-on: https://gitea.com/gitea/runner/pulls/1180 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com> Co-authored-by: bircni <bircni@icloud.com>
This commit is contained in:
committed by
silverwind
co-authored by
silverwind
parent
b97c61aa14
commit
8260e2def2
@@ -0,0 +1,162 @@
|
||||
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//go:build e2e
|
||||
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.com/gitea/runner/internal/app/poll"
|
||||
)
|
||||
|
||||
const runTimeout = 3 * time.Minute
|
||||
|
||||
var nonRepoChars = regexp.MustCompile(`[^a-zA-Z0-9._-]+`)
|
||||
|
||||
func repoName(t *testing.T) string {
|
||||
return strings.ToLower(nonRepoChars.ReplaceAllString(t.Name(), "-"))
|
||||
}
|
||||
|
||||
var fixture *GiteaFixture
|
||||
|
||||
var skipReason string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(runSuite(m))
|
||||
}
|
||||
|
||||
func runSuite(m *testing.M) int {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
cli, err := dockerClient(ctx)
|
||||
if err != nil {
|
||||
skipReason = fmt.Sprintf("docker unavailable: %v", err)
|
||||
return m.Run()
|
||||
}
|
||||
|
||||
f, err := StartGitea(ctx, cli)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "start gitea fixture: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
fixture = f
|
||||
defer func() { _ = fixture.Close(context.Background()) }()
|
||||
|
||||
fmt.Fprintf(os.Stderr, "gitea fixture: image=%s version=%s\n", fixture.image, fixture.version)
|
||||
|
||||
return m.Run()
|
||||
}
|
||||
|
||||
func newScenario(t *testing.T) (*GiteaAPI, string) {
|
||||
t.Helper()
|
||||
|
||||
repo := repoName(t)
|
||||
api := &GiteaAPI{baseURL: fixture.baseURL, token: fixture.adminToken}
|
||||
if err := api.CreateRepo(t.Context(), repo); err != nil {
|
||||
t.Fatalf("create repo: %v", err)
|
||||
}
|
||||
return api, repo
|
||||
}
|
||||
|
||||
func startIsolatedScenario(t *testing.T, workflow, label string, options runnerOptions) (*GiteaAPI, string, *poll.Poller) {
|
||||
t.Helper()
|
||||
|
||||
api, repo := newScenario(t)
|
||||
poller := startRunner(t, repo, label, options)
|
||||
pushWorkflow(t, api, repo, workflow)
|
||||
return api, repo, poller
|
||||
}
|
||||
|
||||
func pushWorkflow(t *testing.T, api *GiteaAPI, repo, workflow string) {
|
||||
t.Helper()
|
||||
|
||||
content, err := os.ReadFile("testdata/workflows/" + workflow)
|
||||
if err != nil {
|
||||
t.Fatalf("read workflow fixture %s: %v", workflow, err)
|
||||
}
|
||||
if err := api.CreateFile(t.Context(), repo, ".gitea/workflows/"+workflow, string(content), "add "+workflow); err != nil {
|
||||
t.Fatalf("push workflow %s: %v", workflow, err)
|
||||
}
|
||||
}
|
||||
|
||||
func requireSuccess(t *testing.T, api *GiteaAPI, repo string, runID int64) {
|
||||
t.Helper()
|
||||
|
||||
completed, err := api.WaitForRunConclusion(t.Context(), repo, runID, runTimeout)
|
||||
if err != nil {
|
||||
dumpRunLogs(t, api, repo, runID)
|
||||
t.Fatalf("wait for run: %v", err)
|
||||
}
|
||||
if completed.Conclusion != "success" {
|
||||
dumpRunLogs(t, api, repo, runID)
|
||||
t.Fatalf("run concluded %q, want success", completed.Conclusion)
|
||||
}
|
||||
}
|
||||
|
||||
func runLogs(t *testing.T, api *GiteaAPI, repo string, runID int64) string {
|
||||
t.Helper()
|
||||
ctx := t.Context()
|
||||
|
||||
jobs, err := api.Jobs(ctx, repo, runID)
|
||||
if err != nil {
|
||||
t.Fatalf("list jobs: %v", err)
|
||||
}
|
||||
var all strings.Builder
|
||||
for _, job := range jobs {
|
||||
logs, err := api.JobLogs(ctx, repo, job.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("job logs for %s: %v", job.Name, err)
|
||||
}
|
||||
all.WriteString(logs)
|
||||
}
|
||||
return all.String()
|
||||
}
|
||||
|
||||
func dumpRunLogs(t *testing.T, api *GiteaAPI, repo string, runID int64) {
|
||||
t.Helper()
|
||||
ctx := t.Context()
|
||||
|
||||
jobs, err := api.Jobs(ctx, repo, runID)
|
||||
if err != nil {
|
||||
t.Logf("dump run %d: list jobs: %v", runID, err)
|
||||
return
|
||||
}
|
||||
for _, job := range jobs {
|
||||
logs, err := api.JobLogs(ctx, repo, job.ID)
|
||||
if err != nil {
|
||||
t.Logf("job %q (%s): logs unavailable: %v", job.Name, job.Conclusion, err)
|
||||
continue
|
||||
}
|
||||
t.Logf("job %q concluded %q:\n%s", job.Name, job.Conclusion, logs)
|
||||
}
|
||||
}
|
||||
|
||||
func waitForRun(t *testing.T, api *GiteaAPI, repo string) *ActionRun {
|
||||
t.Helper()
|
||||
ctx, cancel := context.WithTimeout(t.Context(), time.Minute)
|
||||
defer cancel()
|
||||
|
||||
for {
|
||||
runs, err := api.Runs(ctx, repo)
|
||||
if err != nil {
|
||||
t.Fatalf("get latest run: %v", err)
|
||||
}
|
||||
if len(runs) > 0 {
|
||||
return &runs[0]
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Fatalf("no run appeared for %s within timeout", repo)
|
||||
case <-time.After(pollInterval):
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user