107 lines
4.5 KiB
Go
107 lines
4.5 KiB
Go
package index
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
func manifestPull(t *testing.T, number int, head, manifest string) delivery.Forge {
|
|
f := delivery.Forge{V: delivery.Version, Kind: delivery.ForgePull, Repository: catalogueRepo, Branch: "feat/x", Number: number, Head: head,
|
|
Action: delivery.PullUpdated, Dirs: []string{"modules/avahi"}, DirsKnown: true}
|
|
if manifest != "" {
|
|
f.Manifests = map[string]string{"modules/avahi": manifest}
|
|
}
|
|
return f
|
|
}
|
|
|
|
func candidateOf(t *testing.T, st *memStore) delivery.Candidate {
|
|
t.Helper()
|
|
key, err := delivery.CandidatesKey("feat/x")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
raw, ok := st.vals[key]
|
|
if !ok {
|
|
t.Fatalf("candidates holds %d keys, none %s", len(st.vals), key)
|
|
}
|
|
c, err := delivery.DecodeCandidate(raw)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return c
|
|
}
|
|
|
|
func TestACandidateGivesEachTouchedModuleItsManifestAndTheReasonItHasNoPreview(t *testing.T) { // 1451/AC1
|
|
avahi := catalogueManifest(t, "avahi")
|
|
ix, _, _ := manifestsIndexer(t, rec(t, "build-1", "avahi", catalogueRepo, "modules/avahi", "main", "", "2026-10-19T09:00:00Z", aInputs))
|
|
if err := ix.Apply(context.Background(), manifestPull(t, 301, h1, avahi)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c := candidateOf(t, ix.Store.(*memStore)) // DecodeCandidate has run Candidate.check
|
|
want := delivery.CandidateModule{Manifest: delivery.ManifestDigest([]byte(avahi)), None2: "no merge preview is computed"}
|
|
if len(c.Pulls) != 1 || len(c.Pulls[0].Fps) != 1 || !reflect.DeepEqual(c.Pulls[0].Fps["avahi"], want) {
|
|
t.Fatalf("pulls = %+v, want Fps[avahi] = %+v", c.Pulls, want)
|
|
}
|
|
if c.FPSet == "" || c.FPSet != delivery.FingerprintSet(c.Pulls) {
|
|
t.Errorf("fpset = %q, want %q", c.FPSet, delivery.FingerprintSet(c.Pulls))
|
|
}
|
|
// The same pull request heard again without its directories (the head unchanged) keeps what it had.
|
|
again := manifestPull(t, 301, h1, "")
|
|
again.Dirs, again.DirsKnown = nil, false
|
|
if err := ix.Apply(context.Background(), again); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if c2 := candidateOf(t, ix.Store.(*memStore)); !reflect.DeepEqual(c2.Pulls[0].Fps["avahi"], want) || c2.FPSet != c.FPSet {
|
|
t.Errorf("after a message without directories: %+v fpset %q", c2.Pulls[0].Fps, c2.FPSet)
|
|
}
|
|
}
|
|
|
|
func TestAPullWithoutManifestsWritesTheCandidateAsToday(t *testing.T) { // 1451/AC2
|
|
ix, _, _ := manifestsIndexer(t, rec(t, "build-1", "avahi", catalogueRepo, "modules/avahi", "main", "", "2026-10-19T09:00:00Z", aInputs))
|
|
if err := ix.Apply(context.Background(), manifestPull(t, 301, h1, "")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c := candidateOf(t, ix.Store.(*memStore))
|
|
if len(c.Pulls) != 1 || c.Pulls[0].Fps != nil || c.FPSet != "" || len(c.Pulls[0].Modules) != 1 || c.Pulls[0].Modules[0] != "avahi" {
|
|
t.Errorf("candidate = %+v, want the module avahi and no Fps and no fpset", c)
|
|
}
|
|
}
|
|
|
|
func TestTwoPullsGivingOneModuleDifferentManifestsAreRefusedNamingBoth(t *testing.T) { // 1451/AC3
|
|
avahi := catalogueManifest(t, "avahi")
|
|
// The second pull request carries avahi's manifest changed (a line added at its end) for the same directory.
|
|
other := avahi + "\n"
|
|
ix, _, _ := manifestsIndexer(t, rec(t, "build-1", "avahi", catalogueRepo, "modules/avahi", "main", "", "2026-10-19T09:00:00Z", aInputs))
|
|
if err := ix.Apply(context.Background(), manifestPull(t, 301, h1, avahi)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
before := candidateOf(t, ix.Store.(*memStore))
|
|
writes := ix.Store.(*memStore).writes
|
|
err := ix.Apply(context.Background(), manifestPull(t, 302, h2, other))
|
|
if !errors.Is(err, ErrUnreadable) {
|
|
t.Fatalf("err = %v, want a refusal", err)
|
|
}
|
|
for _, w := range []string{catalogueRepo + "#301", catalogueRepo + "#302", `"avahi"`} {
|
|
if !strings.Contains(err.Error(), w) {
|
|
t.Errorf("the refusal %q does not name %s", err, w)
|
|
}
|
|
}
|
|
// Candidate.check refuses the group too, which is what the refusal stands for.
|
|
if _, encErr := delivery.EncodeCandidate(delivery.Candidate{V: delivery.Version, Group: "feat.x", HeadsHash: before.HeadsHash, Pulls: []delivery.CandidatePull{before.Pulls[0], {
|
|
Head: delivery.Head{Repository: catalogueRepo, Number: 302, Head: h2}, Modules: []string{"avahi"},
|
|
Fps: map[string]delivery.CandidateModule{"avahi": {Manifest: delivery.ManifestDigest([]byte(other)), None2: NoneNoPreview}}}}}); encErr == nil {
|
|
t.Error("the candidate check accepts two manifests for one module")
|
|
}
|
|
if ix.Store.(*memStore).writes != writes {
|
|
t.Error("a partial write was made")
|
|
}
|
|
if after := candidateOf(t, ix.Store.(*memStore)); len(after.Pulls) != 1 || after.FPSet != before.FPSet {
|
|
t.Errorf("the candidate changed: %+v", after)
|
|
}
|
|
}
|