Files

154 lines
5.4 KiB
Go

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")
}
}