| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "encoding/json" |
| 6 | "os" |
| 7 | "path/filepath" |
| 8 | "testing" |
| 9 | |
| 10 | "reasonix/internal/session" |
| 11 | ) |
| 12 | |
| 13 | func TestDesktopStoredPreviewFormatsPreserveOriginalAndMessageIdentity(t *testing.T) { |
| 14 | for _, codec := range []string{session.PrototypeCodec, session.LegacyLinearCodec, session.FinalV31Codec, session.Codec} { |
| 15 | t.Run(codec, func(t *testing.T) { |
| 16 | isolateDesktopUserDirs(t) |
| 17 | root := t.TempDir() |
| 18 | path := filepath.Join(root, "historical") |
| 19 | store, err := session.CreateStore(path, "historical") |
| 20 | if err != nil { |
| 21 | t.Fatal(err) |
| 22 | } |
| 23 | payload := json.RawMessage(`{"message":{"id":"unchanged-message","role":"user","content":"preview history"}}`) |
| 24 | if _, err := store.Append(t.Context(), session.Batch{OperationID: "content", Events: []session.Event{{Kind: "message/complete", Payload: payload}}}); err != nil { |
| 25 | t.Fatal(err) |
| 26 | } |
| 27 | if err := store.Close(t.Context()); err != nil { |
| 28 | t.Fatal(err) |
| 29 | } |
| 30 | commits, err := session.Replay(path, nil) |
| 31 | if err != nil { |
| 32 | t.Fatal(err) |
| 33 | } |
| 34 | body, err := os.ReadFile(filepath.Join(path, "manifest.json")) |
| 35 | if err != nil { |
| 36 | t.Fatal(err) |
| 37 | } |
| 38 | var manifest session.Manifest |
| 39 | if err := json.Unmarshal(body, &manifest); err != nil { |
| 40 | t.Fatal(err) |
| 41 | } |
| 42 | manifest.Codec, manifest.StorageRevision = codec, 0 |
| 43 | if codec != session.Codec { |
| 44 | manifest.SchemaVersion = 3 |
| 45 | var log bytes.Buffer |
| 46 | for _, commit := range commits { |
| 47 | commit.SchemaVersion = 3 |
| 48 | commit.Codec = codec |
| 49 | line, _ := json.Marshal(commit) |
| 50 | log.Write(line) |
| 51 | log.WriteByte('\n') |
| 52 | } |
| 53 | if err := os.WriteFile(filepath.Join(path, "events.jsonl"), log.Bytes(), 0600); err != nil { |
| 54 | t.Fatal(err) |
| 55 | } |
| 56 | } |
| 57 | body, _ = json.Marshal(manifest) |
| 58 | if err := os.WriteFile(filepath.Join(path, "manifest.json"), body, 0600); err != nil { |
| 59 | t.Fatal(err) |
| 60 | } |
| 61 | before, err := desktopSourceFingerprint(path) |
| 62 | if err != nil { |
| 63 | t.Fatal(err) |
| 64 | } |
| 65 | app := NewApp() |
| 66 | app.ctx = t.Context() |
| 67 | pinDesktopSessionRoot(t, app) |
| 68 | source := desktopMigrationSource{root: root, scope: "global"} |
| 69 | if err := app.migrateCanonicalStore(t.Context(), source); err != nil { |
| 70 | t.Fatal(err) |
| 71 | } |
| 72 | if err := app.migrateCanonicalStore(t.Context(), source); err != nil { |
| 73 | t.Fatalf("repeat: %v", err) |
| 74 | } |
| 75 | state, err := app.workspaceRegistry().Load(t.Context()) |
| 76 | if err != nil { |
| 77 | t.Fatal(err) |
| 78 | } |
| 79 | mapping, ok := state.SourceMappings[desktopSourceKey(path, "")] |
| 80 | if !ok || len(state.Workspaces["global"].SessionIDs) != 1 { |
| 81 | t.Fatalf("preview not registered: %+v", state) |
| 82 | } |
| 83 | messages, err := app.desktopSessionService("").Query().History(t.Context(), session.SessionRef{HostID: localDesktopHostID, SessionID: mapping.SessionID}) |
| 84 | if err != nil || len(messages) != 1 || messages[0].ID != "unchanged-message" || messages[0].Content != "preview history" { |
| 85 | t.Fatalf("history=%+v err=%v", messages, err) |
| 86 | } |
| 87 | after, err := desktopSourceFingerprint(path) |
| 88 | if err != nil || before != after { |
| 89 | t.Fatal("historical preview was modified") |
| 90 | } |
| 91 | }) |
| 92 | } |
| 93 | } |
| 94 |