122 lines
4.0 KiB
Go
122 lines
4.0 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|