@@ -0,0 +1,121 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gardomatic.kleiax.de/internal/mailer"
|
||||
"gardomatic.kleiax.de/internal/storage"
|
||||
)
|
||||
|
||||
type applicationSettingsTestModel struct {
|
||||
settings storage.ApplicationSettings
|
||||
calls int
|
||||
asOf time.Time
|
||||
}
|
||||
|
||||
func (m *applicationSettingsTestModel) Get() (storage.ApplicationSettings, error) {
|
||||
return m.settings, nil
|
||||
}
|
||||
func (m *applicationSettingsTestModel) Update(value storage.ApplicationSettings) (storage.ApplicationSettings, error) {
|
||||
m.settings = value
|
||||
return value, nil
|
||||
}
|
||||
func (m *applicationSettingsTestModel) RemoveExpiredPlants(asOf time.Time, _, _ int) (int, error) {
|
||||
m.calls++
|
||||
m.asOf = asOf
|
||||
return 2, nil
|
||||
}
|
||||
|
||||
func TestLifecycleMaintenanceHonorsEnabledSettingAndCutoff(t *testing.T) {
|
||||
app, _, _ := newGardenTestApplication()
|
||||
model := &applicationSettingsTestModel{settings: storage.ApplicationSettings{LifecycleStatusEnabled: true, LifecycleRemovalMonth: 12, LifecycleRemovalDay: 1, Timezone: "Europe/Berlin"}}
|
||||
app.models.ApplicationSettings = model
|
||||
|
||||
if err := app.runLifecycleMaintenance(time.Date(2026, 11, 30, 12, 0, 0, 0, time.UTC)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if model.calls != 0 {
|
||||
t.Fatalf("maintenance ran before cutoff")
|
||||
}
|
||||
if err := app.runLifecycleMaintenance(time.Date(2026, 12, 1, 12, 0, 0, 0, time.UTC)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if model.calls != 1 || model.asOf.Format("2006-01-02") != "2026-12-01" {
|
||||
t.Fatalf("maintenance calls=%d cutoff=%v", model.calls, model.asOf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowAdminEnvironmentMasksSecrets(t *testing.T) {
|
||||
app, _, _ := newGardenTestApplication()
|
||||
app.config = Config{
|
||||
DB: DatabaseConfig{Dsn: "postgres://user:secret@db/gardomatic"},
|
||||
Mail: mailer.Config{Password: "smtp-secret"},
|
||||
}
|
||||
response := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, "/v1/admin/environment", nil)
|
||||
|
||||
app.showAdminEnvironmentHandler(response, request)
|
||||
|
||||
if response.Code != http.StatusOK {
|
||||
t.Fatalf("status: got %d, want %d", response.Code, http.StatusOK)
|
||||
}
|
||||
body := response.Body.String()
|
||||
if strings.Contains(body, "secret") {
|
||||
t.Fatalf("environment response exposes a secret: %s", body)
|
||||
}
|
||||
var result struct {
|
||||
Variables []environmentVariable `json:"variables"`
|
||||
}
|
||||
if err := json.Unmarshal(response.Body.Bytes(), &result); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, name := range []string{"GARDOMATIC_DB_DSN", "GARDOMATIC_SMTP_PASSWORD", "GARDOMATIC_SMTP_SENDER"} {
|
||||
found := false
|
||||
for _, variable := range result.Variables {
|
||||
found = found || variable.Name == name
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("missing environment variable %s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendAdminTestMailValidatesAndDelivers(t *testing.T) {
|
||||
app, _, _ := newGardenTestApplication()
|
||||
mailPath := filepath.Join(t.TempDir(), "mail.log")
|
||||
configuredMailer, err := mailer.New(mailer.Config{Mode: mailer.ModeFile, Sender: "gardomatic@example.com", FilePath: mailPath})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
app.mailer = configuredMailer
|
||||
|
||||
invalidResponse := httptest.NewRecorder()
|
||||
invalidRequest := httptest.NewRequest(http.MethodPost, "/v1/admin/test-mail", strings.NewReader(`{"email":"not-an-email"}`))
|
||||
app.sendAdminTestMailHandler(invalidResponse, invalidRequest)
|
||||
if invalidResponse.Code != http.StatusUnprocessableEntity {
|
||||
t.Fatalf("invalid status: got %d, want %d; body: %s", invalidResponse.Code, http.StatusUnprocessableEntity, invalidResponse.Body.String())
|
||||
}
|
||||
|
||||
response := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodPost, "/v1/admin/test-mail", strings.NewReader(`{"email":" Test@Example.com "}`))
|
||||
app.sendAdminTestMailHandler(response, request)
|
||||
if response.Code != http.StatusAccepted {
|
||||
t.Fatalf("status: got %d, want %d; body: %s", response.Code, http.StatusAccepted, response.Body.String())
|
||||
}
|
||||
content, err := os.ReadFile(mailPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range []string{"test@example.com", "Gardomatic Testmail", "Gardomatic funktion"} {
|
||||
if !strings.Contains(string(content), want) {
|
||||
t.Errorf("test mail is missing %q: %s", want, content)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user