embed_test.go
1 package agents 2 3 import ( 4 "io/fs" 5 "os" 6 "path/filepath" 7 "sort" 8 "testing" 9 ) 10 11 func TestEnsureBuiltins_CreatesOnFirstRun(t *testing.T) { 12 dir := t.TempDir() 13 agentsDir := filepath.Join(dir, "agents") 14 os.MkdirAll(agentsDir, 0700) 15 16 err := EnsureBuiltins(agentsDir, "0.0.99-test") 17 if err != nil { 18 t.Fatalf("EnsureBuiltins: %v", err) 19 } 20 21 // Verify explorer 22 data, err := os.ReadFile(filepath.Join(agentsDir, "_builtin", "explorer", "AGENT.md")) 23 if err != nil { 24 t.Fatalf("explorer AGENT.md missing: %v", err) 25 } 26 if len(data) == 0 { 27 t.Fatal("explorer AGENT.md is empty") 28 } 29 30 // Verify reviewer 31 data, err = os.ReadFile(filepath.Join(agentsDir, "_builtin", "reviewer", "AGENT.md")) 32 if err != nil { 33 t.Fatalf("reviewer AGENT.md missing: %v", err) 34 } 35 if len(data) == 0 { 36 t.Fatal("reviewer AGENT.md is empty") 37 } 38 39 // Verify version file 40 ver, err := os.ReadFile(filepath.Join(agentsDir, "_builtin", ".version")) 41 if err != nil { 42 t.Fatalf(".version missing: %v", err) 43 } 44 if string(ver) != "0.0.99-test" { 45 t.Fatalf("expected version 0.0.99-test, got %s", string(ver)) 46 } 47 } 48 49 func TestEnsureBuiltins_SkipsWhenVersionMatches(t *testing.T) { 50 dir := t.TempDir() 51 agentsDir := filepath.Join(dir, "agents") 52 os.MkdirAll(agentsDir, 0700) 53 54 // First run 55 EnsureBuiltins(agentsDir, "0.0.99") 56 57 // Modify a file to detect if it gets overwritten 58 marker := filepath.Join(agentsDir, "_builtin", "explorer", "AGENT.md") 59 os.WriteFile(marker, []byte("modified"), 0600) 60 61 // Second run with same version 62 EnsureBuiltins(agentsDir, "0.0.99") 63 64 data, _ := os.ReadFile(marker) 65 if string(data) != "modified" { 66 t.Fatal("EnsureBuiltins overwrote files when version matched") 67 } 68 } 69 70 func TestEnsureBuiltins_OverwritesOnVersionChange(t *testing.T) { 71 dir := t.TempDir() 72 agentsDir := filepath.Join(dir, "agents") 73 os.MkdirAll(agentsDir, 0700) 74 75 EnsureBuiltins(agentsDir, "0.0.98") 76 77 marker := filepath.Join(agentsDir, "_builtin", "explorer", "AGENT.md") 78 os.WriteFile(marker, []byte("modified"), 0600) 79 80 // Upgrade 81 EnsureBuiltins(agentsDir, "0.0.99") 82 83 data, _ := os.ReadFile(marker) 84 if string(data) == "modified" { 85 t.Fatal("EnsureBuiltins did not overwrite on version change") 86 } 87 } 88 89 func TestMaterializeBuiltin(t *testing.T) { 90 dir := t.TempDir() 91 agentsDir := filepath.Join(dir, "agents") 92 93 builtinDir := filepath.Join(agentsDir, "_builtin", "explorer") 94 os.MkdirAll(builtinDir, 0700) 95 os.WriteFile(filepath.Join(builtinDir, "AGENT.md"), []byte("builtin prompt"), 0600) 96 os.WriteFile(filepath.Join(builtinDir, "config.yaml"), []byte("tools:\n allow: [bash]"), 0600) 97 98 userDir := filepath.Join(agentsDir, "explorer") 99 if _, err := os.Stat(filepath.Join(userDir, "AGENT.md")); err == nil { 100 t.Fatal("user dir should not exist before materialization") 101 } 102 103 err := MaterializeBuiltin(agentsDir, "explorer") 104 if err != nil { 105 t.Fatalf("MaterializeBuiltin: %v", err) 106 } 107 108 data, err := os.ReadFile(filepath.Join(userDir, "AGENT.md")) 109 if err != nil || string(data) != "builtin prompt" { 110 t.Fatalf("AGENT.md not materialized correctly") 111 } 112 data, err = os.ReadFile(filepath.Join(userDir, "config.yaml")) 113 if err != nil || string(data) != "tools:\n allow: [bash]" { 114 t.Fatalf("config.yaml not materialized correctly") 115 } 116 } 117 118 func TestBuiltinNames_MatchEmbeddedDirs(t *testing.T) { 119 entries, err := fs.ReadDir(builtinFS, "builtin") 120 if err != nil { 121 t.Fatalf("reading embedded FS: %v", err) 122 } 123 var embedded []string 124 for _, e := range entries { 125 if e.IsDir() { 126 embedded = append(embedded, e.Name()) 127 } 128 } 129 sort.Strings(embedded) 130 131 names := make([]string, len(BuiltinNames)) 132 copy(names, BuiltinNames) 133 sort.Strings(names) 134 135 if len(embedded) != len(names) { 136 t.Fatalf("BuiltinNames has %d entries but embedded FS has %d dirs: embedded=%v names=%v", 137 len(names), len(embedded), embedded, names) 138 } 139 for i := range embedded { 140 if embedded[i] != names[i] { 141 t.Fatalf("mismatch at index %d: embedded=%q names=%q", i, embedded[i], names[i]) 142 } 143 } 144 } 145 146 func TestMaterializeBuiltin_SkipsMemory(t *testing.T) { 147 dir := t.TempDir() 148 agentsDir := filepath.Join(dir, "agents") 149 builtinDir := filepath.Join(agentsDir, "_builtin", "explorer") 150 os.MkdirAll(builtinDir, 0700) 151 os.WriteFile(filepath.Join(builtinDir, "AGENT.md"), []byte("prompt"), 0600) 152 os.WriteFile(filepath.Join(builtinDir, "MEMORY.md"), []byte("should not copy"), 0600) 153 154 MaterializeBuiltin(agentsDir, "explorer") 155 156 userDir := filepath.Join(agentsDir, "explorer") 157 if _, err := os.Stat(filepath.Join(userDir, "MEMORY.md")); err == nil { 158 t.Fatal("MEMORY.md should not be materialized") 159 } 160 }