package podbackend import ( "context" "testing" runnerv1 "gitea.dev/actionslib/runner/v1" "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 fakeAPI struct { pods []Pod selector string created PodManifest entry IdentityEntry entryGone string deleted string marked map[string]string } func (a *fakeAPI) ListPods(_ context.Context, _ string, selector string) ([]Pod, error) { a.selector = selector return a.pods, nil } func (a *fakeAPI) CreatePod(_ context.Context, manifest PodManifest) (Pod, error) { a.created = manifest return Pod{Name: manifest.Name, Namespace: manifest.Namespace, UID: "pod-uid", Phase: "Pending"}, nil } func (a *fakeAPI) DeletePod(_ context.Context, _, name string) error { a.deleted = name return nil } func (a *fakeAPI) LabelPod(_ context.Context, _, _ string, labels map[string]string) error { a.marked = labels return nil } func (a *fakeAPI) EnsureIdentityEntry(_ context.Context, entry IdentityEntry) error { a.entry = entry return nil } func (a *fakeAPI) DeleteIdentityEntry(_ context.Context, name string) error { a.entryGone = name return nil } func backend(api API) Backend { return Backend{API: api, Config: Config{ Namespace: "gitea-actions", Image: "zot/ci-executor:main", ServiceAccount: "gitea-task-executor", ExecutorArgs: []string{"executor"}, TrustDomain: "ddupan.top", SPIRECluster: "homelab", SPIREClass: "spire-mgmt-spire", SPIREAgentID: "spiffe://ddupan.top/spire/agent/k8s_psat/homelab/node-uid", ExecutorUID: 2000, }} } func assignment() taskassignment.Assignment { return taskassignment.Assignment{ ID: "gitea-task-42", Backend: taskassignment.BackendPod, Task: &runnerv1.Task{Id: 42}, Identity: taskidentity.Identity{ Repository: "owner/repo", Task: "publish", SPIFFEID: "spiffe://ddupan.top/ci/owner/repo/publish", }, } } func TestFindRecoversPodByAssignmentLabel(t *testing.T) { api := &fakeAPI{pods: []Pod{{Name: "gitea-task-42", UID: "uid", Phase: "Running"}}} executor, err := backend(api).Find(context.Background(), "gitea-task-42") if err != nil { t.Fatal(err) } if api.selector != "ci.ddupan.top/assignment-id=gitea-task-42" || executor.Name != "gitea-task-42" || executor.IdentityTarget != "uid" || executor.Phase != taskworker.PhaseRunning { t.Fatalf("selector=%q executor=%#v", api.selector, executor) } } func TestCreateUsesDeterministicNameAndRecoveryMetadata(t *testing.T) { api := &fakeAPI{} metadata := taskworker.BackendMetadata(assignment()) executor, err := backend(api).Create(context.Background(), assignment(), taskworker.LaunchSpec{ Metadata: metadata, Environment: map[string]string{"CI_RUNNER_CAPABILITY": "capability"}, }) if err != nil { t.Fatal(err) } if api.created.Name != "gitea-task-42" || api.created.Labels[assignmentLabel] != "gitea-task-42" { t.Fatalf("manifest = %#v", api.created) } if api.created.Annotations["ci.ddupan.top/spiffe-id"] != assignment().Identity.SPIFFEID { t.Fatalf("annotations = %#v", api.created.Annotations) } if api.created.Environment["CI_RUNNER_CAPABILITY"] != "capability" { t.Fatalf("environment = %#v", api.created.Environment) } if len(api.created.Args) != 1 || api.created.Args[0] != "executor" || executor.IdentityTarget != "pod-uid" { t.Fatalf("args=%v executor=%#v", api.created.Args, executor) } } func TestBindIdentityCreatesEntryPinnedToPodUID(t *testing.T) { api := &fakeAPI{} executor := &taskworker.Executor{Name: "gitea-task-42", IdentityTarget: "pod-uid"} if err := backend(api).BindIdentity(context.Background(), executor, assignment().Identity); err != nil { t.Fatal(err) } if api.entry.Name != executor.Name || api.entry.SPIFFEID != assignment().Identity.SPIFFEID || api.entry.ParentID != "spiffe://ddupan.top/spire/agent/k8s_psat/homelab/node-uid" || len(api.entry.Selectors) != 1 || api.entry.Selectors[0] != "k8s:pod-uid:pod-uid" { t.Fatalf("entry=%#v", api.entry) } } func TestDeleteRemovesIdentityBeforePod(t *testing.T) { api := &fakeAPI{} executor := &taskworker.Executor{Name: "gitea-task-42", IdentityTarget: "pod-uid"} if err := backend(api).Delete(context.Background(), executor); err != nil { t.Fatal(err) } if api.entryGone != executor.Name || api.deleted != executor.Name { t.Fatalf("entry=%q pod=%q", api.entryGone, api.deleted) } } func TestTerminalMarkerAndCleanupUseBackendState(t *testing.T) { api := &fakeAPI{pods: []Pod{ {Name: "running", UID: "running-uid", Phase: "Running"}, {Name: "finished", UID: "finished-uid", Phase: "Succeeded"}, }} backend := backend(api) if err := backend.MarkTerminal(context.Background(), "gitea-task-42"); err != nil { t.Fatal(err) } if api.marked[terminalLabel] != "true" { t.Fatalf("labels = %#v", api.marked) } cleaned, err := backend.CleanupTerminated(context.Background()) if err != nil { t.Fatal(err) } if api.selector != terminalLabel+"=true" || cleaned != 1 || api.deleted != "finished" || api.entryGone != "finished" { t.Fatalf("selector=%q cleaned=%d deleted=%q entry=%q", api.selector, cleaned, api.deleted, api.entryGone) } } func TestFindRejectsDuplicatePods(t *testing.T) { api := &fakeAPI{pods: []Pod{{Name: "one"}, {Name: "two"}}} if _, err := backend(api).Find(context.Background(), "gitea-task-42"); err == nil { t.Fatal("expected duplicate executor error") } }