1package extensions
2
3import (
4 "context"
5 "errors"
6 "os"
7 "os/exec"
8 "path/filepath"
9 "strings"
10 "testing"
11)
12
13func TestLoadErrorsIdentifyExtensionDirectory(t *testing.T) {
14 for _, explicit := range []bool{false, true} {
15 mode := "discover"
16 if explicit {
17 mode = "explicit"
18 }
19 for _, tc := range []struct {
20 name string
21 manifest string
22 want string
23 }{
24 {"invalid-json", `{`, "parse manifest"},
25 {"missing-name", `{"exec":"missing"}`, "name is required"},
26 {"missing-exec", `{"name":"broken"}`, "exec, theme, or skills is required"},
27 {"open-log", `{"name":"broken","exec":"missing"}`, "open log"},
28 {"missing-runtime", `{"name":"broken","exec":"zot-test-missing-runtime"}`, "failed to start"},
29 } {
30 t.Run(mode+"/"+tc.name, func(t *testing.T) {
31 home := t.TempDir()
32 dir := filepath.Join(home, "extensions", tc.name)
33 if err := os.MkdirAll(dir, 0o755); err != nil {
34 t.Fatal(err)
35 }
36 if err := os.WriteFile(filepath.Join(dir, "extension.json"), []byte(tc.manifest), 0o644); err != nil {
37 t.Fatal(err)
38 }
39 if tc.name == "open-log" {
40 if err := os.WriteFile(filepath.Join(home, "logs"), nil, 0o644); err != nil {
41 t.Fatal(err)
42 }
43 }
44 if tc.name == "missing-runtime" {
45 t.Setenv("PATH", t.TempDir())
46 }
47 mgr := New(home, "", "test", "", "", nil)
48 var errs []error
49 if explicit {
50 errs = mgr.LoadExplicit(context.Background(), []string{dir})
51 } else {
52 errs = mgr.Discover(context.Background())
53 }
54 if len(errs) != 1 {
55 t.Fatalf("errors = %v, want one", errs)
56 }
57 if got := errs[0].Error(); !strings.Contains(got, dir) || !strings.Contains(got, tc.want) {
58 t.Fatalf("error = %q, want directory %q and %q", got, dir, tc.want)
59 }
60 if tc.name == "missing-runtime" {
61 if !errors.Is(errs[0], exec.ErrNotFound) {
62 t.Fatalf("error does not wrap exec.ErrNotFound: %v", errs[0])
63 }
64 if strings.Count(errs[0].Error(), dir) != 1 {
65 t.Fatalf("directory should appear once: %v", errs[0])
66 }
67 }
68 })
69 }
70 }
71}