~bigbes/sr-ht-spec

ref: ef7bddf8b3d64cb4c204a064ad73dbacc78443cb sr-ht-spec/service/review_test.go -rw-r--r-- 5.1 KiB
ef7bddf8 — Eugene Blikh ci: publish the apk into artifacts.sr.ht as well 3 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package service

import (
	"bytes"
	"context"
	"testing"
	"time"

	"sourcecraft.dev/bigbes/sr-ht-spec/core"
)

// TestDigestMark proves the digest mark round-trips through the owner-keyed
// store and that its absence is reported as "no mark yet" rather than an error —
// the distinction the inbox turns into "every auto-merge is new on first view".
func TestDigestMark(t *testing.T) {
	svc, _ := newTestService(t)
	ctx := context.Background()

	if _, marked, err := svc.DigestMark(ctx); err != nil || marked {
		t.Fatalf("DigestMark before any write: marked=%v err=%v, want (false, nil)", marked, err)
	}

	seen := time.Date(2026, 7, 20, 15, 0, 0, 0, time.UTC)
	if err := svc.MarkDigestSeen(ctx, seen); err != nil {
		t.Fatalf("MarkDigestSeen: %v", err)
	}

	got, marked, err := svc.DigestMark(ctx)
	if err != nil || !marked {
		t.Fatalf("DigestMark after write: marked=%v err=%v, want (true, nil)", marked, err)
	}
	if !got.Equal(seen) {
		t.Errorf("mark = %s, want %s", got, seen)
	}
}

// TestInboxAndDigest proves the instance-wide queues: an open proposal lands in
// the inbox, a policy-auto-merged one lands in the digest, and neither shows in
// the other.
func TestInboxAndDigest(t *testing.T) {
	svc, _ := newTestService(t)
	ctx := context.Background()
	sp, err := svc.CreateSpace(ctx, fxSpace)
	if err != nil {
		t.Fatalf("CreateSpace: %v", err)
	}
	// A policy that auto-merges notes/, so one proposal lands and one waits.
	commitFiles(t, sp, sp.ApprovedBranch(), 1, map[string][]byte{
		".spec.yml": []byte("review:\n  auto_merge: [notes/**]\n"),
	})
	base, err := sp.Repo.ApprovedHead(ctx)
	if err != nil {
		t.Fatalf("ApprovedHead: %v", err)
	}

	// Auto-merges (notes/).
	auto, err := svc.Propose(ctx, ProposeRequest{
		Space: fxSpace, Principal: agentPrincipal(), Title: "note", IfMatch: base.String(),
		Message: "note", Writes: []DocumentWrite{{Path: "notes/a.md", Content: mdDoc("N-1", "A", "b")}},
	})
	if err != nil || !auto.Merged {
		t.Fatalf("auto-merge propose: merged=%v err=%v", auto.Merged, err)
	}
	// Stays open (specs/).
	open, err := svc.Propose(ctx, ProposeRequest{
		Space: fxSpace, Principal: agentPrincipal(), Title: "spec", IfMatch: base.String(),
		Message: "spec", Writes: []DocumentWrite{{Path: "specs/b.md", Content: mdDoc("S-1", "B", "c")}},
	})
	if err != nil || open.Merged {
		t.Fatalf("open propose: merged=%v err=%v", open.Merged, err)
	}

	inbox, err := svc.InboxProposals(ctx)
	if err != nil {
		t.Fatalf("InboxProposals: %v", err)
	}
	if len(inbox) != 1 || inbox[0].ID != open.Proposal.ID {
		t.Fatalf("inbox = %+v, want only the open proposal %d", inbox, open.Proposal.ID)
	}

	digest, err := svc.DigestProposals(ctx, 0)
	if err != nil {
		t.Fatalf("DigestProposals: %v", err)
	}
	if len(digest) != 1 || digest[0].ID != auto.Proposal.ID || digest[0].Approval != core.ApprovalPolicy {
		t.Fatalf("digest = %+v, want only the policy-merged proposal %d", digest, auto.Proposal.ID)
	}
}

// TestProposalDiffReturnsChangedDocuments proves ProposalDiff returns exactly
// the documents a proposal changes — a modified one with its base and proposed
// content, and an added one marked new — and not the documents it leaves alone.
func TestProposalDiffReturnsChangedDocuments(t *testing.T) {
	svc, _ := newTestService(t)
	ctx := context.Background()
	sp, err := svc.CreateSpace(ctx, fxSpace)
	if err != nil {
		t.Fatalf("CreateSpace: %v", err)
	}
	// The approved head carries two documents; the proposal edits one, adds a
	// third, and leaves the second untouched.
	commitFiles(t, sp, sp.ApprovedBranch(), 1, map[string][]byte{
		"specs/a.md":    mdDoc("S-1", "A", "original body"),
		"specs/keep.md": mdDoc("S-2", "Keep", "unchanged body"),
	})
	base, err := sp.Repo.ApprovedHead(ctx)
	if err != nil {
		t.Fatalf("ApprovedHead: %v", err)
	}
	res, err := svc.Propose(ctx, ProposeRequest{
		Space:     fxSpace,
		Principal: agentPrincipal(),
		Title:     "edit and add",
		IfMatch:   base.String(),
		Message:   "two changes",
		Writes: []DocumentWrite{
			{Path: "specs/a.md", Content: mdDoc("S-1", "A", "revised body")},
			{Path: "specs/new.md", Content: mdDoc("S-3", "New", "brand new body")},
		},
	})
	if err != nil {
		t.Fatalf("Propose: %v", err)
	}

	docs, err := svc.ProposalDiff(ctx, res.Proposal)
	if err != nil {
		t.Fatalf("ProposalDiff: %v", err)
	}
	byPath := make(map[string]ProposalDoc, len(docs))
	for _, d := range docs {
		byPath[d.Path] = d
	}
	if _, ok := byPath["specs/keep.md"]; ok {
		t.Errorf("ProposalDiff returned the untouched specs/keep.md")
	}

	edited, ok := byPath["specs/a.md"]
	if !ok {
		t.Fatalf("ProposalDiff missing the edited document")
	}
	if edited.New {
		t.Errorf("specs/a.md marked new, want an edit")
	}
	if !bytes.Contains(edited.Base, []byte("original body")) {
		t.Errorf("edited doc base = %q, want the approved content", edited.Base)
	}
	if !bytes.Contains(edited.Proposed, []byte("revised body")) {
		t.Errorf("edited doc proposed = %q, want the proposal content", edited.Proposed)
	}

	added, ok := byPath["specs/new.md"]
	if !ok {
		t.Fatalf("ProposalDiff missing the added document")
	}
	if !added.New || added.Base != nil {
		t.Errorf("added doc = %+v, want New with a nil base", added)
	}
}