oficina / sheets Public

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

Plain git — no account needed to clone.

Download

Download this file

1package store_test
2
3import (
4 "bytes"
5 "context"
6 "path/filepath"
7 "strings"
8 "testing"
9
10 "amadan.net/oficina/sheets/internal/sheets"
11 "amadan.net/oficina/sheets/internal/sheets/calc"
12 "amadan.net/oficina/sheets/internal/sheets/seal"
13 "amadan.net/oficina/sheets/internal/sheets/store"
14 rdb "amadan.net/rastrillo/rastrillo/db"
15 "amadan.net/rastrillo/rastrillo/migrate"
16)
17
18func TestVersionWatermarkMigrationPreservesExistingContent(t *testing.T) {
19 d, err := rdb.Open(filepath.Join(t.TempDir(), "old.db"), nil)
20 if err != nil {
21 t.Fatal(err)
22 }
23 defer d.Close()
24 old := &migrate.Set{}
25 for _, m := range sheets.BootSchema.All() {
26 if !strings.HasPrefix(m.ID, "sheets/") || m.ID <= "sheets/0009_alter_formats_ink_intent" {
27 old.Add(m)
28 }
29 }
30 if _, err := migrate.Apply(context.Background(), d, old); err != nil {
31 t.Fatal(err)
32 }
33 s, err := seal.New(make32())
34 if err != nil {
35 t.Fatal(err)
36 }
37 name, err := s.Seal("tab.name", []byte("Original tab"))
38 if err != nil {
39 t.Fatal(err)
40 }
41 raw, err := s.Seal("cell.input", []byte("5"))
42 if err != nil {
43 t.Fatal(err)
44 }
45 cache, err := s.Seal("cell.cached", store.EncodeValueForTest(calc.Value{Kind: calc.KindNum, Num: 5}))
46 if err != nil {
47 t.Fatal(err)
48 }
49 payload, err := s.Seal("event.payload", []byte(`{"r":100,"c":200,"o":"","n":"5"}`))
50 if err != nil {
51 t.Fatal(err)
52 }
53 for _, q := range []struct {
54 sql string
55 args []any
56 }{
57 {"INSERT INTO events (id,tab_id,kind,actor_id,payload_sealed) VALUES (?,?,?,?,?)", []any{1, tabID, "input", actor, payload}},
58 {"INSERT INTO tabs (id,sheet_id,name_sealed,position) VALUES (?,?,?,?)", []any{tabID, 1, name, 0}},
59 {"INSERT INTO rows (id,tab_id,position) VALUES (?,?,?)", []any{rowA, tabID, 0}},
60 {"INSERT INTO cols (id,tab_id,position) VALUES (?,?,?)", []any{colA, tabID, 0}},
61 {"INSERT INTO cells (tab_id,row_id,col_id,input_sealed,cached_sealed,input_version,cache_version) VALUES (?,?,?,?,?,?,?)", []any{tabID, rowA, colA, raw, cache, 700, 700}},
62 } {
63 if err := d.G.Exec(q.sql, q.args...).Error; err != nil {
64 t.Fatal(err)
65 }
66 }
67 if _, err := migrate.Apply(context.Background(), d, sheets.BootSchema); err != nil {
68 t.Fatal(err)
69 }
70 var event store.Event
71 if err := d.G.First(&event, 1).Error; err != nil {
72 t.Fatal(err)
73 }
74 if !bytes.Equal(event.PayloadSealed, payload) || event.ActorID != actor {
75 t.Fatal("migration altered history")
76 }
77 var mark uint64
78 if err := d.G.Raw("SELECT content_version FROM tabs WHERE id = ?", tabID).Scan(&mark).Error; err != nil {
79 t.Fatal(err)
80 }
81 if mark != 0 {
82 t.Fatalf("new watermark default=%d", mark)
83 }
84 var cell store.Cell
85 if err := d.G.First(&cell).Error; err != nil {
86 t.Fatal(err)
87 }
88 if !bytes.Equal(cell.InputSealed, raw) || !bytes.Equal(cell.CachedSealed, cache) {
89 t.Fatal("migration altered encrypted cell")
90 }
91 var tab store.Tab
92 if err := d.G.First(&tab, tabID).Error; err != nil {
93 t.Fatal(err)
94 }
95 if !bytes.Equal(tab.NameSealed, name) {
96 t.Fatal("migration altered encrypted name")
97 }
98 h, err := store.Open(d.G, s, tabID)
99 if err != nil {
100 t.Fatal(err)
101 }
102 clear, err := h.SetReport(rowA, colA, "", actor)
103 if err != nil {
104 t.Fatal(err)
105 }
106 h.Release()
107 if clear.Version <= 700 {
108 t.Fatalf("ignored old cell stamp: %d", clear.Version)
109 }
110 h, err = store.Open(d.G, s, tabID)
111 if err != nil {
112 t.Fatal(err)
113 }
114 defer h.Release()
115 next, err := h.SetReport(rowA, colA, "6", actor)
116 if err != nil {
117 t.Fatal(err)
118 }
119 if next.Version <= clear.Version {
120 t.Fatalf("post-upgrade versions %d -> %d", clear.Version, next.Version)
121 }
122}
123