Files
gitea-dynamic-runner/internal/opensandboxbackend/backend_test.go
panxiao81 87cf359ef6
test / shell (pull_request) Successful in 26s
test / go (pull_request) Successful in 2m58s
test / python (pull_request) Failing after 14m15s
fix: 标记 OpenSandbox Runner workload
2026-09-21 08:22:56 +00:00

151 lines
5.7 KiB
Go

package opensandboxbackend
import (
"context"
"testing"
runnerv1 "gitea.dev/actionslib/runner/v1"
opensandbox "github.com/alibaba/OpenSandbox/sdks/sandbox/go"
"git.ddupan.top/panxiao81/gitea-dynamic-runner/internal/taskassignment"
"git.ddupan.top/panxiao81/gitea-dynamic-runner/internal/taskidentity"
"git.ddupan.top/panxiao81/gitea-dynamic-runner/internal/taskworker"
)
type fakeLifecycle struct {
items []opensandbox.SandboxInfo
created opensandbox.CreateSandboxRequest
deleted string
}
func (f *fakeLifecycle) ListSandboxes(context.Context, opensandbox.ListOptions) (*opensandbox.ListSandboxesResponse, error) {
return &opensandbox.ListSandboxesResponse{Items: f.items}, nil
}
func (f *fakeLifecycle) CreateSandbox(_ context.Context, request opensandbox.CreateSandboxRequest) (*opensandbox.SandboxInfo, error) {
f.created = request
return &opensandbox.SandboxInfo{ID: "sandbox-42", Status: opensandbox.SandboxStatus{State: opensandbox.StatePending}, Metadata: request.Metadata}, nil
}
func (f *fakeLifecycle) GetSandbox(_ context.Context, id string) (*opensandbox.SandboxInfo, error) {
for _, item := range f.items {
if item.ID == id {
return &item, nil
}
}
metadata, _ := encodeAnnotations(map[string]string{"ci.ddupan.top/spiffe-id": assignment().Identity.SPIFFEID})
return &opensandbox.SandboxInfo{ID: id, Metadata: metadata}, nil
}
func (f *fakeLifecycle) PatchSandboxMetadata(_ context.Context, id string, patch opensandbox.MetadataPatch) (*opensandbox.SandboxInfo, error) {
for index := range f.items {
if f.items[index].ID != id {
continue
}
if f.items[index].Metadata == nil {
f.items[index].Metadata = map[string]string{}
}
for key, value := range patch {
if value != nil {
f.items[index].Metadata[key] = *value
}
}
return &f.items[index], nil
}
return &opensandbox.SandboxInfo{ID: id}, nil
}
func (f *fakeLifecycle) DeleteSandbox(_ context.Context, id string) error { f.deleted = id; return nil }
func backend(lifecycle Lifecycle) Backend {
return Backend{Lifecycle: lifecycle, Config: Config{
Pool: "ci-vm", Timeout: 14400,
Entrypoint: []string{"/usr/local/bin/gitea-task-executor"},
Env: map[string]string{"SPIFFE_ENDPOINT_SOCKET": "unix:///run/spire/agent-sockets/spire-agent.sock"},
}}
}
func assignment() taskassignment.Assignment {
return taskassignment.Assignment{
ID: "gitea-task-42", Backend: taskassignment.BackendVM,
Task: &runnerv1.Task{Id: 42},
Identity: taskidentity.Identity{Repository: "owner/repo", Task: "publish", SPIFFEID: "spiffe://ddupan.top/ci/owner/repo/publish"},
}
}
func TestFindRecoversSandboxByMetadata(t *testing.T) {
lifecycle := &fakeLifecycle{items: []opensandbox.SandboxInfo{{ID: "sandbox-42", Status: opensandbox.SandboxStatus{State: opensandbox.StateRunning}}}}
executor, err := backend(lifecycle).Find(context.Background(), assignment().ID)
if err != nil || executor.Name != "sandbox-42" || executor.Phase != taskworker.PhaseRunning {
t.Fatalf("executor=%#v err=%v", executor, err)
}
}
func TestCreateUsesPoolAndPersistsRecoveryMetadata(t *testing.T) {
lifecycle := &fakeLifecycle{}
metadata := taskworker.BackendMetadata(assignment())
executor, err := backend(lifecycle).Create(context.Background(), assignment(), taskworker.LaunchSpec{
Metadata: metadata,
Environment: map[string]string{
"CI_SPIFFE_ID": assignment().Identity.SPIFFEID,
"CI_RUNNER_CAPABILITY": "capability",
},
})
if err != nil {
t.Fatal(err)
}
if lifecycle.created.Extensions["poolRef"] != "ci-vm" || lifecycle.created.Metadata[assignmentMetadata] != assignment().ID || lifecycle.created.Metadata["ci.ddupan.top/runner"] != "true" || lifecycle.created.Env["CI_SPIFFE_ID"] != assignment().Identity.SPIFFEID || executor.Name != "sandbox-42" {
t.Fatalf("request=%#v executor=%#v", lifecycle.created, executor)
}
if lifecycle.created.Env["CI_RUNNER_CAPABILITY"] != "capability" {
t.Fatalf("environment = %#v", lifecycle.created.Env)
}
annotations, err := decodeAnnotations(lifecycle.created.Metadata)
if err != nil || annotations["ci.ddupan.top/repository"] != "owner/repo" || annotations["ci.ddupan.top/spiffe-id"] != assignment().Identity.SPIFFEID {
t.Fatalf("annotations=%#v err=%v", annotations, err)
}
for _, value := range lifecycle.created.Metadata {
if len(value) > metadataValueLimit {
t.Fatalf("metadata value exceeds %d characters: %q", metadataValueLimit, value)
}
}
}
func TestAnnotationMetadataRoundTripPreservesSlashValues(t *testing.T) {
want := taskworker.BackendMetadata(assignment()).Annotations
encoded, err := encodeAnnotations(want)
if err != nil {
t.Fatal(err)
}
got, err := decodeAnnotations(encoded)
if err != nil {
t.Fatal(err)
}
for key, value := range want {
if got[key] != value {
t.Fatalf("%s=%q, want %q", key, got[key], value)
}
}
}
func TestBindIdentityVerifiesPersistedMetadata(t *testing.T) {
lifecycle := &fakeLifecycle{}
if err := backend(lifecycle).BindIdentity(context.Background(), &taskworker.Executor{Name: "sandbox-42"}, assignment().Identity); err != nil {
t.Fatal(err)
}
}
func TestTerminalMarkerDrivesDurableCleanup(t *testing.T) {
lifecycle := &fakeLifecycle{items: []opensandbox.SandboxInfo{{
ID: "sandbox-42",
Metadata: map[string]string{assignmentMetadata: assignment().ID},
}}}
backend := backend(lifecycle)
if err := backend.MarkTerminal(context.Background(), assignment().ID); err != nil {
t.Fatal(err)
}
if lifecycle.items[0].Metadata[terminalMetadata] != "true" {
t.Fatalf("metadata = %#v", lifecycle.items[0].Metadata)
}
cleaned, err := backend.CleanupTerminated(context.Background())
if err != nil || cleaned != 1 || lifecycle.deleted != "sandbox-42" {
t.Fatalf("cleaned=%d deleted=%q err=%v", cleaned, lifecycle.deleted, err)
}
}