aboutsummaryrefslogtreecommitdiff
path: root/protocol/v0v1/server/receivepack/report_status_test.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-07 14:24:05 +0800
committerGravatar Runxi Yu2026-03-07 17:01:46 +0800
commit4b8d39764f9b54ea3090d0fea92a23025dbea30d (patch)
treecaa6e408c4ea625afcbb1b4aa4fb9e945f46994b /protocol/v0v1/server/receivepack/report_status_test.go
parentrefstore: Split files (diff)
signatureNo signature
protocol: Add v0v1 server protocol and its receivepack subprotocol
Diffstat (limited to 'protocol/v0v1/server/receivepack/report_status_test.go')
-rw-r--r--protocol/v0v1/server/receivepack/report_status_test.go189
1 files changed, 189 insertions, 0 deletions
diff --git a/protocol/v0v1/server/receivepack/report_status_test.go b/protocol/v0v1/server/receivepack/report_status_test.go
new file mode 100644
index 00000000..fa76a85b
--- /dev/null
+++ b/protocol/v0v1/server/receivepack/report_status_test.go
@@ -0,0 +1,189 @@
+package receivepack_test
+
+import (
+ "errors"
+ "strings"
+ "testing"
+
+ "codeberg.org/lindenii/furgit/format/pktline"
+ "codeberg.org/lindenii/furgit/format/sideband64k"
+ "codeberg.org/lindenii/furgit/internal/testgit"
+ "codeberg.org/lindenii/furgit/objectid"
+ common "codeberg.org/lindenii/furgit/protocol/v0v1/server"
+ receivepack "codeberg.org/lindenii/furgit/protocol/v0v1/server/receivepack"
+)
+
+func TestWriteReportStatusWritesClassicStatus(t *testing.T) {
+ t.Parallel()
+
+ var out bufferWriteFlusher
+
+ base := common.NewSession(strings.NewReader(""), &out, common.Options{})
+ session := receivepack.NewSession(base, receivepack.Capabilities{})
+
+ err := session.WriteReportStatus(receivepack.ReportStatusResult{
+ Commands: []receivepack.CommandResult{
+ {Name: "refs/heads/main"},
+ {Name: "refs/heads/dev", Error: "non-fast-forward"},
+ },
+ })
+ if err != nil {
+ t.Fatalf("WriteReportStatus: %v", err)
+ }
+
+ got := out.String()
+ wantParts := []string{
+ "unpack ok\n",
+ "ok refs/heads/main\n",
+ "ng refs/heads/dev non-fast-forward\n",
+ "0000",
+ }
+
+ for _, part := range wantParts {
+ if !strings.Contains(got, part) {
+ t.Fatalf("report-status missing %q in %q", part, got)
+ }
+ }
+}
+
+func TestWriteReportStatusUsesSideBand64KWhenNegotiated(t *testing.T) {
+ t.Parallel()
+
+ //nolint:thelper
+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
+ t.Parallel()
+
+ var requestWire bufferWriteFlusher
+
+ requestEnc := pktline.NewEncoder(&requestWire)
+
+ err := requestEnc.WriteData([]byte(
+ objectid.Zero(algo).String() + " " + mustHexID(t, algo, "1").String() + " refs/heads/main\x00report-status side-band-64k object-format=" + algo.String() + "\n",
+ ))
+ if err != nil {
+ t.Fatalf("WriteData(request): %v", err)
+ }
+
+ err = requestEnc.WriteFlush()
+ if err != nil {
+ t.Fatalf("WriteFlush(request): %v", err)
+ }
+
+ var out bufferWriteFlusher
+
+ base := common.NewSession(strings.NewReader(requestWire.String()), &out, common.Options{
+ Algorithm: algo,
+ })
+ session := receivepack.NewSession(base, receivepack.Capabilities{
+ ReportStatus: true,
+ SideBand64K: true,
+ ObjectFormat: algo,
+ })
+
+ _, err = session.ReadRequest()
+ if err != nil {
+ t.Fatalf("ReadRequest: %v", err)
+ }
+
+ err = session.WriteReportStatus(receivepack.ReportStatusResult{
+ Commands: []receivepack.CommandResult{
+ {Name: "refs/heads/main"},
+ },
+ })
+ if err != nil {
+ t.Fatalf("WriteReportStatus: %v", err)
+ }
+
+ dec := sideband64k.NewDecoder(strings.NewReader(out.String()), sideband64k.ReadOptions{})
+
+ frame, err := dec.ReadFrame()
+ if err != nil {
+ t.Fatalf("ReadFrame(unpack): %v", err)
+ }
+
+ if frame.Type != sideband64k.FrameData || string(frame.Payload) != "unpack ok\n" {
+ t.Fatalf("first frame = %#v", frame)
+ }
+
+ frame, err = dec.ReadFrame()
+ if err != nil {
+ t.Fatalf("ReadFrame(ok): %v", err)
+ }
+
+ if frame.Type != sideband64k.FrameData || string(frame.Payload) != "ok refs/heads/main\n" {
+ t.Fatalf("second frame = %#v", frame)
+ }
+
+ frame, err = dec.ReadFrame()
+ if err != nil {
+ t.Fatalf("ReadFrame(flush): %v", err)
+ }
+
+ if frame.Type != sideband64k.FrameFlush {
+ t.Fatalf("flush frame.Type = %v, want FrameFlush", frame.Type)
+ }
+ })
+}
+
+func TestWriteReportStatusV2WritesOptionLines(t *testing.T) {
+ t.Parallel()
+
+ //nolint:thelper
+ testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
+ t.Parallel()
+
+ oldID := mustHexID(t, algo, "1")
+ newID := mustHexID(t, algo, "2")
+
+ var out bufferWriteFlusher
+
+ base := common.NewSession(strings.NewReader(""), &out, common.Options{})
+ session := receivepack.NewSession(base, receivepack.Capabilities{})
+
+ err := session.WriteReportStatusV2(receivepack.ReportStatusResult{
+ Commands: []receivepack.CommandResult{
+ {
+ Name: "refs/pseudo/proc",
+ RefName: "refs/heads/main",
+ OldID: &oldID,
+ NewID: &newID,
+ ForcedUpdate: true,
+ },
+ {Name: "refs/heads/dev", Error: "rejected"},
+ },
+ })
+ if err != nil {
+ t.Fatalf("WriteReportStatusV2: %v", err)
+ }
+
+ got := out.String()
+ wantParts := []string{
+ "unpack ok\n",
+ "ok refs/pseudo/proc\n",
+ "option refname refs/heads/main\n",
+ "option old-oid " + oldID.String() + "\n",
+ "option new-oid " + newID.String() + "\n",
+ "option forced-update\n",
+ "ng refs/heads/dev rejected\n",
+ "0000",
+ }
+
+ for _, part := range wantParts {
+ if !strings.Contains(got, part) {
+ t.Fatalf("report-status-v2 missing %q in %q", part, got)
+ }
+ }
+ })
+}
+
+func TestWriteProgressRequiresSideBand64K(t *testing.T) {
+ t.Parallel()
+
+ base := common.NewSession(strings.NewReader(""), &bufferWriteFlusher{}, common.Options{})
+ session := receivepack.NewSession(base, receivepack.Capabilities{})
+
+ err := session.WriteProgress([]byte("progress\n"))
+ if !errors.Is(err, common.ErrSideBandNotEnabled) {
+ t.Fatalf("WriteProgress error = %v, want %v", err, common.ErrSideBandNotEnabled)
+ }
+}