package app import ( "io" "log/slog" "net/http" "net/http/httptest" "net/url" "os" "path/filepath" "strings" "testing" "github.com/example/glpi-env-controller/internal/dockerctl" ) func testTemplate(t *testing.T) string { t.Helper() data, err := os.ReadFile("../../cmd/env-controller/page.html") if err != nil { t.Fatal(err) } return string(data) } func TestSaveCreatesBackupAndKeepsUnrevealedSecret(t *testing.T) { dir := t.TempDir() envPath := filepath.Join(dir, ".env") examplePath := filepath.Join(dir, ".env.example") backupDir := filepath.Join(dir, "backups") if err := os.WriteFile(envPath, []byte("A=1\nWEB_PASSWORD=top-secret\n"), 0o600); err != nil { t.Fatal(err) } if err := os.WriteFile(examplePath, []byte("A=0\nWEB_PASSWORD=placeholder\n"), 0o600); err != nil { t.Fatal(err) } project := ProjectConfig{ID: "test", Title: "Test", EnvFile: envPath, ExampleFile: examplePath, BackupDir: backupDir} cfg := Config{Username: "admin", MaxBackups: 10, DockerTimeout: "1s", Projects: []ProjectConfig{project}} server, err := NewServer(cfg, "password", testTemplate(t), slog.New(slog.NewTextHandler(io.Discard, nil))) if err != nil { t.Fatal(err) } form := url.Values{"csrf": {server.csrf}, "v.A": {"2"}, "v.WEB_PASSWORD": {unchangedSecret}} req := httptest.NewRequest(http.MethodPost, "/project/test/save", strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth("admin", "password") res := httptest.NewRecorder() server.Handler().ServeHTTP(res, req) if res.Code != http.StatusOK { t.Fatalf("status %d: %s", res.Code, res.Body.String()) } got, err := os.ReadFile(envPath) if err != nil { t.Fatal(err) } if string(got) != "A=2\nWEB_PASSWORD=top-secret\n" { t.Fatalf("unexpected env: %q", got) } entries, err := os.ReadDir(backupDir) if err != nil { t.Fatal(err) } found := false for _, entry := range entries { if strings.HasSuffix(entry.Name(), ".env") { found = true } } if !found { t.Fatal("expected backup") } } func TestTargetPickerTemplateExecutes(t *testing.T) { cfg := Config{Username: "admin", MaxBackups: 10, DockerTimeout: "1s", Projects: []ProjectConfig{{ID: "test"}}} server, err := NewServer(cfg, "password", testTemplate(t), slog.New(slog.NewTextHandler(io.Discard, nil))) if err != nil { t.Fatal(err) } data := pageData{Title: "x", CSRF: server.csrf, Project: &projectView{Config: ProjectConfig{ID: "test"}, Targets: []targetView{{Target: dockerctl.Target{ContainerName: "agent", DisplayName: "Agent", AllowedActions: []string{"restart", "recreate"}, DefaultAction: "recreate", ApplyByDefault: true}, Status: dockerctl.Status{State: "running"}}}}} var b strings.Builder if err := server.tpl.ExecuteTemplate(&b, "page", data); err != nil { t.Fatal(err) } if !strings.Contains(b.String(), "glpi") && !strings.Contains(b.String(), "agent") { t.Fatal("target not rendered") } }