repository_test.go RawHistoryFolder

1package snapshot
2
3import (
4	"context"
5	"crypto/sha256"
6	"testing"
7
8	"github.com/bnema/vev/internal/domain"
9
10	"github.com/bnema/vev/internal/ports"
11	codec "github.com/bnema/vev/internal/usecase/snapshot"
12)
13
14func TestRepositoryPublishesAndLoadsCompleteGeneration(t *testing.T) {
15	t.Parallel()
16	dir := privateDir(t)
17	repo := NewRepository(dir)
18	pub := repositoryPublication(t, "named", 1, []byte("state"))
19	if err := repo.Publish(context.Background(), pub); err != nil {
20		t.Fatalf("Publish: %v", err)
21	}
22	got, err := loadPublication(context.Background(), repo, pub)
23	if err != nil {
24		t.Fatalf("Load: %v", err)
25	}
26	if got.Name != "named" || got.Generation != 1 || len(got.Objects) != 2 {
27		t.Fatalf("Load = %#v", got)
28	}
29}
30
31func loadPublication(ctx context.Context, repo *Repository, publication ports.SnapshotPublication) (ports.SnapshotGeneration, error) {
32	return repo.LoadCheckpoint(ctx, publication.IncarnationID, publication.Name, ports.CheckpointRef{
33		Generation:     publication.Generation,
34		ManifestDigest: codec.ManifestDigest(publication.Manifest),
35	})
36}
37
38func repositoryPublicationAfter(t *testing.T, repo *Repository, name string, generation uint64, payload []byte) ports.SnapshotPublication {
39	t.Helper()
40	return publicationWithCurrentParent(t, repo, repositoryPublication(t, name, generation, payload))
41}
42
43// publicationWithCurrentParent requires repositories to contain HEAD for every
44// publication after generation one. Callers such as prepareHeadStage and
45// seedCompletePublication must seed or publish the parent generation first.
46func publicationWithCurrentParent(t *testing.T, repo *Repository, publication ports.SnapshotPublication) ports.SnapshotPublication {
47	t.Helper()
48	if publication.Generation == 1 {
49		return publication
50	}
51	currentGeneration, digest, err := repo.readHead(publication.IncarnationID)
52	if err != nil {
53		t.Fatalf("read parent HEAD: %v", err)
54	}
55	parent := &domain.CheckpointRef{Generation: currentGeneration, ManifestDigest: digest}
56	manifest, err := codec.UnmarshalManifest(publication.Manifest)
57	if err != nil {
58		t.Fatal(err)
59	}
60	manifest.ParentCheckpoint = parent
61	publication.Manifest, err = codec.MarshalManifest(manifest)
62	if err != nil {
63		t.Fatal(err)
64	}
65	publication.ParentCheckpoint = parent
66	return publication
67}
68
69func repositoryPublication(t *testing.T, name string, generation uint64, payload []byte) ports.SnapshotPublication {
70	t.Helper()
71	id := testIncarnationID(name)
72	tail, err := codec.MarshalObject(codec.HistoryTail, canonicalHistoryBlob(t, string(payload)))
73	if err != nil {
74		t.Fatal(err)
75	}
76	transcript, err := codec.MarshalObject(codec.RecoveryTranscript, canonicalHistoryBlob(t, "transcript"))
77	if err != nil {
78		t.Fatal(err)
79	}
80	manifest, err := codec.MarshalManifest(codec.Manifest{Generation: generation, IncarnationID: id, Name: name, Tabs: []codec.ManifestTab{{Cols: 1, Rows: 1, Panes: []codec.ManifestPane{{ID: "p", Tail: codec.ObjectRef{Kind: codec.HistoryTail, Digest: tail.Digest, Size: uint32(len(tail.Data))}, Transcript: codec.ObjectRef{Kind: codec.RecoveryTranscript, Digest: transcript.Digest, Size: uint32(len(transcript.Data))}}}}}})
81	if err != nil {
82		t.Fatal(err)
83	}
84	return ports.SnapshotPublication{IncarnationID: id, Name: name, Generation: generation, Manifest: manifest, Objects: []ports.SnapshotObject{tail, transcript}}
85}
86
87func testIncarnationID(name string) domain.IncarnationID {
88	digest := sha256.Sum256([]byte("test incarnation: " + name))
89	var id domain.IncarnationID
90	copy(id[:], digest[:])
91	return id
92}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close