eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1package main
2
3import (
4 "bytes"
5 "context"
6 "os"
7 "path/filepath"
8 "testing"
9
10 "golang.org/x/crypto/acme/autocert"
11)
12
13// testCertCacheConformance is the contract every cache backend (dir today, S3
14// later) must satisfy — autocert and the wildcard manager rely on all three:
15// Get/Put round-trip, ErrCacheMiss (not a bare error) for an absent key, and
16// idempotent Delete.
17func testCertCacheConformance(t *testing.T, cache autocert.Cache) {
18 t.Helper()
19 ctx := context.Background()
20
21 if _, err := cache.Get(ctx, "absent"); err != autocert.ErrCacheMiss {
22 t.Fatalf("Get(absent) = %v, want ErrCacheMiss", err)
23 }
24 want := []byte("pem-bytes")
25 if err := cache.Put(ctx, "chat.example.com", want); err != nil {
26 t.Fatal(err)
27 }
28 if got, err := cache.Get(ctx, "chat.example.com"); err != nil || !bytes.Equal(got, want) {
29 t.Fatalf("Get after Put = %q, %v", got, err)
30 }
31 // Overwrite is the renewal path.
32 if err := cache.Put(ctx, "chat.example.com", []byte("renewed")); err != nil {
33 t.Fatal(err)
34 }
35 if got, _ := cache.Get(ctx, "chat.example.com"); string(got) != "renewed" {
36 t.Fatalf("overwrite lost: %q", got)
37 }
38 if err := cache.Delete(ctx, "chat.example.com"); err != nil {
39 t.Fatal(err)
40 }
41 if _, err := cache.Get(ctx, "chat.example.com"); err != autocert.ErrCacheMiss {
42 t.Fatalf("Get after Delete = %v, want ErrCacheMiss", err)
43 }
44 if err := cache.Delete(ctx, "never-existed"); err != nil {
45 t.Fatalf("Delete(absent) = %v, want nil", err)
46 }
47}
48
49func TestNewCertCacheDirBackend(t *testing.T) {
50 dir := t.TempDir()
51 t.Setenv("LCHAT_CERT_CACHE", "") // unset = dir
52 cache, err := newCertCache(dir)
53 if err != nil {
54 t.Fatal(err)
55 }
56 testCertCacheConformance(t, cache)
57
58 // The dir backend must be byte-identical to the pre-seam layout: a key is
59 // a plain file name inside the acme cache dir, 0600 (every entry may hold
60 // private key material) — an existing /data/acme keeps working over a
61 // restart with no migration.
62 ctx := context.Background()
63 if err := cache.Put(ctx, "chat.example.com", []byte("pem")); err != nil {
64 t.Fatal(err)
65 }
66 path := filepath.Join(dir, "chat.example.com")
67 if raw, err := os.ReadFile(path); err != nil || string(raw) != "pem" {
68 t.Fatalf("on-disk layout drifted: %q, %v", raw, err)
69 }
70 if fi, err := os.Stat(path); err != nil || fi.Mode().Perm() != 0o600 {
71 t.Fatalf("cert file mode = %v, err %v (want 0600)", fi.Mode(), err)
72 }
73 // And the reverse: a cert file an older binary wrote directly is served.
74 if err := os.WriteFile(filepath.Join(dir, "old.example.com"), []byte("old"), 0o600); err != nil {
75 t.Fatal(err)
76 }
77 if raw, err := cache.Get(ctx, "old.example.com"); err != nil || string(raw) != "old" {
78 t.Fatalf("pre-seam file not readable through the cache: %q, %v", raw, err)
79 }
80}
81
82func TestNewCertCacheEnvSelection(t *testing.T) {
83 t.Setenv("LCHAT_CERT_CACHE", "dir")
84 if _, err := newCertCache(t.TempDir()); err != nil {
85 t.Fatalf("explicit dir backend: %v", err)
86 }
87 // s3 is reserved: refusing to start beats a router silently minting certs
88 // into a local dir the rest of a pool can't see.
89 t.Setenv("LCHAT_CERT_CACHE", "s3")
90 if _, err := newCertCache(t.TempDir()); err == nil {
91 t.Fatal("s3 backend accepted before it exists")
92 }
93 t.Setenv("LCHAT_CERT_CACHE", "floppy")
94 if _, err := newCertCache(t.TempDir()); err == nil {
95 t.Fatal("unknown backend accepted")
96 }
97}
98