artifacts/internal/pull/pull_test.go

173 lines
3.7 KiB
Go
Raw Permalink Normal View History

2026-09-13 19:10:04 +02:00
package pull
import (
"archive/zip"
"os"
"path/filepath"
"reflect"
"testing"
"code.geekeey.de/actions/sdk"
)
func TestParseConfig(t *testing.T) {
t.Parallel()
cases := []struct {
name string
env map[string]string
want *config
wantErr bool
}{
{
name: "default path",
env: map[string]string{"name": "foo"},
want: &config{Name: "foo", Path: "."},
},
{
name: "explicit path",
env: map[string]string{"name": "foo", "path": "out"},
want: &config{Name: "foo", Path: "out"},
},
{
name: "other repository",
env: map[string]string{
"name": "foo", "repository": "owner/repo", "run-id": "42", "github-token": "tok",
},
want: &config{Name: "foo", Path: ".", Repository: "owner/repo", RunID: "42", Token: "tok"},
},
{
name: "missing name",
env: map[string]string{},
wantErr: true,
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := parseConfig(func(k string) string { return tc.env[k] })
if tc.wantErr {
if err == nil {
t.Fatalf("expected error, got %+v", got)
}
return
}
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("expected %+v, got %+v", tc.want, got)
}
})
}
}
func TestUseRepositoryAPI(t *testing.T) {
t.Parallel()
gh := &sdk.GitHubContext{Repository: "owner/repo", RunID: "100"}
cases := []struct {
name string
cfg *config
want bool
}{
{"current", &config{Repository: "owner/repo", RunID: "100"}, false},
{"empty means current", &config{}, false},
{"other repository", &config{Repository: "other/repo", RunID: "100"}, true},
{"other run", &config{Repository: "owner/repo", RunID: "200"}, true},
{"repository only matches", &config{Repository: "owner/repo"}, false},
{"repository only differs", &config{Repository: "other/repo"}, true},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
if got := useRepositoryAPI(tc.cfg, gh); got != tc.want {
t.Errorf("expected %v, got %v", tc.want, got)
}
})
}
}
func TestExtractArchive(t *testing.T) {
t.Parallel()
zipPath := filepath.Join(t.TempDir(), "artifact.zip")
writeZip(t, zipPath, map[string]string{
"a.txt": "a",
"sub/b.txt": "b",
})
dest := t.TempDir()
if err := extractArchive(zipPath, dest); err != nil {
t.Fatal(err)
}
for name, want := range map[string]string{"a.txt": "a", "sub/b.txt": "b"} {
got, err := os.ReadFile(filepath.Join(dest, name))
if err != nil {
t.Fatal(err)
}
if string(got) != want {
t.Errorf("expected %q to contain %q, got %q", name, want, got)
}
}
}
func TestExtractArchive_PathTraversal(t *testing.T) {
t.Parallel()
zipPath := filepath.Join(t.TempDir(), "artifact.zip")
writeZip(t, zipPath, map[string]string{"../evil.txt": "evil"})
if err := extractArchive(zipPath, t.TempDir()); err == nil {
t.Fatal("expected error for path traversal entry")
}
}
func TestDownloadPath(t *testing.T) {
t.Parallel()
abs := t.TempDir()
if got := downloadPath(abs); got != abs {
t.Errorf("expected %q, got %q", abs, got)
}
wd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
if got, want := downloadPath("out"), filepath.Join(wd, "out"); got != want {
t.Errorf("expected %q, got %q", want, got)
}
}
func writeZip(t *testing.T, path string, files map[string]string) {
t.Helper()
f, err := os.Create(path)
if err != nil {
t.Fatal(err)
}
defer f.Close()
zw := zip.NewWriter(f)
for name, content := range files {
w, err := zw.Create(name)
if err != nil {
t.Fatal(err)
}
if _, err := w.Write([]byte(content)); err != nil {
t.Fatal(err)
}
}
if err := zw.Close(); err != nil {
t.Fatal(err)
}
}