Files

166 lines
4.8 KiB
Go

package runtimecodex
import (
"context"
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"inbox/internal/app/runtimeconfig"
"inbox/internal/domain/role"
"inbox/internal/domain/skill"
)
type fakeRoleCatalog struct {
roles []role.Definition
}
func (f fakeRoleCatalog) ListRoles(_ context.Context) ([]role.Definition, error) {
return append([]role.Definition(nil), f.roles...), nil
}
type fakeRoleResolver struct {
resolved map[string]runtimeconfig.ResolvedRole
}
func (f fakeRoleResolver) ResolveRole(_ context.Context, _ string, roleName string) (runtimeconfig.ResolvedRole, error) {
return f.resolved[roleName], nil
}
func TestMaterializerSyncWritesRoleConfigs(t *testing.T) {
ctx := context.Background()
root := t.TempDir()
materializer := NewMaterializer(
fakeRoleCatalog{
roles: []role.Definition{
{Name: "worker", Title: "Worker", IsEnabled: true},
{Name: "disabled_role", Title: "Disabled", IsEnabled: false},
},
},
fakeRoleResolver{
resolved: map[string]runtimeconfig.ResolvedRole{
"worker": {
Role: role.Definition{Name: "worker", Title: "Worker", IsEnabled: true},
Config: role.Config{
RoleName: "worker",
ConfigTOML: strings.Join([]string{
`model = "gpt-5.2"`,
`model_provider = "custom"`,
``,
`[shell_environment_policy]`,
`inherit = "core"`,
`exclude = [ ]`,
`include_only = [ ]`,
`experimental_use_profile = false`,
``,
`[shell_environment_policy.set]`,
`XDG_CACHE_HOME = "/tmp/codex-xdg-cache"`,
``,
`[model_providers.custom]`,
`base_url = "http://example.test/v1"`,
`wire_api = "responses"`,
``,
`[mcp_servers.playwright]`,
`enabled = false`,
`command = "npx"`,
`args = [ "-y", "@playwright/mcp@latest" ]`,
`startup_timeout_sec = 90`,
``,
`[projects."/workspace"]`,
`trust_level = "trusted"`,
}, "\n"),
AuthJSON: `{"OPENAI_API_KEY":"token-1"}`,
},
Skills: []runtimeconfig.ResolvedSkill{
{
Skill: skill.Definition{
ID: "builtin-skill-inbox",
SkillKey: "inbox",
ContentMarkdown: "# Inbox\n\nUse inbox.",
},
},
},
},
},
},
)
if err := materializer.Sync(ctx, "ws_1", root); err != nil {
t.Fatalf("Sync() error = %v", err)
}
configPath := filepath.Join(root, filepath.FromSlash(WorkspaceDir), "worker", ".codex", configFilename)
authPath := filepath.Join(root, filepath.FromSlash(WorkspaceDir), "worker", ".codex", authFilename)
configBody, err := os.ReadFile(configPath)
if err != nil {
t.Fatalf("ReadFile(config) error = %v", err)
}
authBody, err := os.ReadFile(authPath)
if err != nil {
t.Fatalf("ReadFile(auth) error = %v", err)
}
if _, err := os.Stat(filepath.Join(root, filepath.FromSlash(WorkspaceDir), "disabled_role")); !os.IsNotExist(err) {
t.Fatalf("disabled role should not have runtime codex home")
}
configText := string(configBody)
for _, needle := range []string{
`model = "gpt-5.2"`,
`model_provider = "custom"`,
`[model_providers.custom]`,
`base_url = "http://example.test/v1"`,
`[mcp_servers.playwright]`,
`[shell_environment_policy.set]`,
`[projects."/workspace"]`,
} {
if !strings.Contains(configText, needle) {
t.Fatalf("expected config to contain %q, got:\n%s", needle, configText)
}
}
var auth map[string]string
if err := json.Unmarshal(authBody, &auth); err != nil {
t.Fatalf("json.Unmarshal(auth) error = %v", err)
}
if auth["OPENAI_API_KEY"] != "token-1" {
t.Fatalf("expected auth OPENAI_API_KEY to be written, got %#v", auth)
}
skillBody, err := os.ReadFile(filepath.Join(root, filepath.FromSlash(WorkspaceDir), "worker", ".codex", "skills", "inbox", "SKILL.md"))
if err != nil {
t.Fatalf("ReadFile(skill) error = %v", err)
}
if string(skillBody) != "# Inbox\n\nUse inbox." {
t.Fatalf("unexpected skill body %q", string(skillBody))
}
}
func TestWriteResolvedRoleHomeWritesOnlyResolvedConfig(t *testing.T) {
root := t.TempDir()
roleHome, err := WriteResolvedRoleHome(root, runtimeconfig.ResolvedRole{
WorkspaceID: "ws_1",
Role: role.Definition{Name: "leader", Title: "Leader", IsEnabled: true},
Config: role.Config{
RoleName: "leader",
ConfigTOML: "model = \"gpt-5.4\"",
AuthJSON: `{"OPENAI_API_KEY":"token-2"}`,
},
})
if err != nil {
t.Fatalf("WriteResolvedRoleHome() error = %v", err)
}
authBody, err := os.ReadFile(filepath.Join(roleHome, ".codex", authFilename))
if err != nil {
t.Fatalf("ReadFile(auth) error = %v", err)
}
var auth map[string]string
if err := json.Unmarshal(authBody, &auth); err != nil {
t.Fatalf("json.Unmarshal(auth) error = %v", err)
}
if auth["OPENAI_API_KEY"] != "token-2" {
t.Fatalf("expected auth OPENAI_API_KEY to be written, got %#v", auth)
}
}