carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package registry
2
3import (
4 "io"
5 "os"
6 "path/filepath"
7 "reflect"
8 "testing"
9)
10
11func TestRemoteReadOnlyWALRegistry(t *testing.T) {
12 if os.Geteuid() == 0 {
13 t.Skip("read-only permission fixture requires a nonroot uid")
14 }
15 t.Setenv("CARLOS_HOST_CLAIM", "true")
16 owner := ClaimOwnership{ClaimIncarnation: "inc", ClaimStamp: 3, ClaimOwner: "owner", ClaimRowID: "route"}
17 dir := t.TempDir()
18 path := filepath.Join(dir, "registry.db")
19 writer, err := Open(path)
20 if err != nil {
21 t.Fatal(err)
22 }
23 defer writer.Close()
24 if err := writer.Upsert(Route{Host: "readonly", Kind: "instance", Account: "acct", App: "app", ClaimOwnership: owner}); err != nil {
25 t.Fatal(err)
26 }
27 timer, err := writer.UpsertTimerRegistration(Timer{Host: "readonly", Name: "backup", Kind: "cron", Spec: "* * * * *"}, "")
28 if err != nil {
29 t.Fatal(err)
30 }
31 if err := writer.ReplaceTimers("orphan", []Timer{{Host: "orphan", Name: "paused", Kind: "cron", NextAt: 0}}); err != nil {
32 t.Fatal(err)
33 }
34 for _, suffix := range []string{"", "-wal", "-shm"} {
35 if err := os.Chmod(path+suffix, 0444); err != nil {
36 t.Fatal(err)
37 }
38 }
39 if err := os.Chmod(dir, 0555); err != nil {
40 t.Fatal(err)
41 }
42 defer func() {
43 os.Chmod(dir, 0755)
44 for _, suffix := range []string{"", "-wal", "-shm"} {
45 os.Chmod(path+suffix, 0644)
46 }
47 }()
48 requestR, requestW := io.Pipe()
49 responseR, responseW := io.Pipe()
50 done := make(chan error, 1)
51 go func() {
52 err := ServeRemoteReadOnly(path, requestR, responseW)
53 requestR.Close()
54 responseW.Close()
55 done <- err
56 }()
57 reader, err := OpenRemote(path, requestW, responseR, func() error { return <-done })
58 if err != nil {
59 t.Fatal(err)
60 }
61 defer reader.Close()
62 hosts, err := reader.ArtifactHosts()
63 if err != nil || !reflect.DeepEqual(hosts, []string{"orphan", "readonly"}) {
64 t.Fatalf("readonly artifact hosts: %v %v", hosts, err)
65 }
66 row, err := reader.Get("readonly")
67 if err != nil || row == nil || row.Account != "acct" || row.App != "app" {
68 t.Fatalf("readonly WAL read: %+v %v", row, err)
69 }
70 timers, err := reader.TimersFor("readonly")
71 if err != nil || len(timers) != 1 || timers[0].Registration != timer.Registration || timers[0].ClaimOwnership != timer.ClaimOwnership || timers[0].ClaimOwner != owner.ClaimOwner || timers[0].ClaimStamp != owner.ClaimStamp {
72 t.Fatalf("readonly timer identity: %+v %v", timers, err)
73 }
74 if err := reader.ReplaceTimers("readonly", nil); err == nil {
75 t.Fatal("read-only worker replaced timers")
76 }
77 if err := reader.DeleteTimer("readonly", "backup"); err == nil {
78 t.Fatal("read-only worker deleted timer")
79 }
80 after, err := reader.TimersFor("readonly")
81 if err != nil || len(after) != 1 || after[0] != timers[0] {
82 t.Fatalf("refused writes changed timer: %+v %v", after, err)
83 }
84 if err := reader.Upsert(Route{Host: "forbidden", Kind: "instance"}); err == nil {
85 t.Fatal("read-only worker accepted mutation")
86 }
87 if _, err := reader.Get("readonly"); err != nil {
88 t.Fatalf("read after refused mutation: %v", err)
89 }
90 if writable, err := Open(path); err == nil {
91 writable.Close()
92 t.Fatal("normal registry open accepted read-only state")
93 }
94}
95