object_compress_test.go RawHistoryFolder

1package snapshotcodec
2
3import (
4	"bytes"
5	"encoding/binary"
6	"errors"
7	"hash/crc32"
8	"testing"
9)
10
11// reframeObject rewrites the VEVO body and fixes length and CRC so a test
12// reaches the payload checks instead of failing on framing.
13func reframeObject(t *testing.T, encoded []byte, mutate func(body []byte) []byte) []byte {
14	t.Helper()
15	body := mutate(append([]byte(nil), encoded[manifestHeaderSize:]...))
16	out := append([]byte(nil), encoded[:manifestHeaderSize]...)
17	binary.BigEndian.PutUint32(out[8:12], uint32(len(body)))
18	binary.BigEndian.PutUint32(out[12:16], crc32.ChecksumIEEE(body))
19	return append(out, body...)
20}
21
22func TestObjectCompressionRejectsMalformedPayloads(t *testing.T) {
23	payload := bytes.Repeat([]byte("history row "), 512)
24	object, err := MarshalObject(HistoryChunk, payload)
25	if err != nil {
26		t.Fatal(err)
27	}
28	if len(object.Data) >= len(payload)/4 {
29		t.Fatalf("object = %d bytes, want well under %d raw bytes", len(object.Data), len(payload))
30	}
31	again, err := MarshalObject(HistoryChunk, payload)
32	if err != nil || !bytes.Equal(again.Data, object.Data) || again.Digest != object.Digest {
33		t.Fatal("equal payloads must share one deterministic content address")
34	}
35
36	for _, tc := range []struct {
37		name   string
38		mutate func(body []byte) []byte
39		want   error
40	}{
41		{name: "declared shorter", mutate: func(b []byte) []byte {
42			binary.BigEndian.PutUint32(b[1:5], uint32(len(payload)-1))
43			return b
44		}, want: ErrInvalidData},
45		{name: "declared longer", mutate: func(b []byte) []byte {
46			binary.BigEndian.PutUint32(b[1:5], uint32(len(payload)+1))
47			return b
48		}, want: ErrInvalidData},
49		{name: "declared maximum on a small stream", mutate: func(b []byte) []byte {
50			binary.BigEndian.PutUint32(b[1:5], maxObjectPayloadSize)
51			return b
52		}, want: ErrInvalidData},
53		{name: "truncated stream", mutate: func(b []byte) []byte { return b[:len(b)-1] }, want: ErrInvalidData},
54		{name: "corrupt stream", mutate: func(b []byte) []byte { b[len(b)-6] ^= 0xff; return b }, want: ErrInvalidData},
55		{name: "trailing garbage", mutate: func(b []byte) []byte { return append(b, 0) }, want: ErrTrailingBytes},
56	} {
57		t.Run(tc.name, func(t *testing.T) {
58			bad := reframeObject(t, object.Data, tc.mutate)
59			if _, err := PreflightObject(bad); err != nil {
60				t.Fatalf("preflight must accept valid framing, got %v", err)
61			}
62			if _, _, err := UnmarshalObject(bad); !errors.Is(err, tc.want) {
63				t.Fatalf("UnmarshalObject() error = %v, want %v", err, tc.want)
64			}
65		})
66	}
67}

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