oficina / calendar Public

Clone
git clone https://amadan.net/oficina/calendar

Plain git — no account needed to clone.

Download

Download this file

1package calendar
2
3import (
4 "context"
5 "io"
6 "log/slog"
7 "net/http"
8 "net/http/httptest"
9 "net/url"
10 "path/filepath"
11 "strings"
12 "sync"
13 "testing"
14)
15
16// panicOnceMailer panics on its first send and records the rest.
17type panicOnceMailer struct {
18 mu sync.Mutex
19 calls int
20 to []string
21}
22
23func (m *panicOnceMailer) Send(_ context.Context, to, _, _ string) error {
24 m.mu.Lock()
25 defer m.mu.Unlock()
26 m.calls++
27 if m.calls == 1 {
28 panic("relay exploded")
29 }
30 m.to = append(m.to, to)
31 return nil
32}
33
34// TestAPanickingMailerDoesNotStopSigninMail is Astra's production-
35// composition probe (round 3 on #28): the sign-in queue's worker hands
36// each link to the bounded sender, which runs the real send on a
37// goroutine of its own — outside the worker's recover. A mailer that
38// panicked there took the whole process down. Built exactly as New
39// builds it, the first link's panic must be contained and the next
40// sign-in's link delivered.
41func TestAPanickingMailerDoesNotStopSigninMail(t *testing.T) {
42 m := &panicOnceMailer{}
43 a, err := New(Config{DBPath: filepath.Join(t.TempDir(), "calendar.db"), Env: "development", Origin: TestOrigin,
44 AllowedAddresses: "one@example.test,two@example.test", Mailer: m, Logger: slog.New(slog.NewTextHandler(io.Discard, nil))})
45 if err != nil {
46 t.Fatal(err)
47 }
48 t.Cleanup(func() { a.Close() })
49 for _, address := range []string{"one@example.test", "two@example.test"} {
50 r := httptest.NewRequest(http.MethodPost, TestOrigin+"/signin", strings.NewReader(url.Values{"address": {address}}.Encode()))
51 r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
52 r.Header.Set("Origin", TestOrigin)
53 a.mux.ServeHTTP(httptest.NewRecorder(), r)
54 a.FlushSigninMailForTest()
55 }
56 m.mu.Lock()
57 defer m.mu.Unlock()
58 if len(m.to) != 1 || m.to[0] != "two@example.test" {
59 t.Fatalf("delivered %v, want the second link after the first send panicked", m.to)
60 }
61}
62