The delivery repository's contracts and SDK live under modules/ as mesh-delivery-contracts and mesh-delivery-sdk, their Go module paths renamed to match the folders (the TypeScript names already did), and every importer in mesh-delivery, mesh-catalog, mesh-host, mesh-tools and mesh-sdk follows in the same group: a design as it should be, one path per module, checked by the group's check building every importer. Builds: design 47 G §427, §88 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
91 lines
3.1 KiB
Go
91 lines
3.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshcatalogclient"
|
|
catalog "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
|
delivery "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshdelivery"
|
|
"git.novox.be/novox/mesh-sdk/go/views"
|
|
)
|
|
|
|
// wiringOf is a part's reader in miniature: it keeps the followers adopted, so a test starts them as the reader's Start does.
|
|
type wiringOf struct {
|
|
mu sync.Mutex
|
|
fs []*views.Follower
|
|
}
|
|
|
|
func (w *wiringOf) Adopt(f *views.Follower, _, _ string, _ func(context.Context, []byte) error) error {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
w.fs = append(w.fs, f)
|
|
return nil
|
|
}
|
|
func (w *wiringOf) Drop(string, string) error { return nil }
|
|
|
|
// Design 47 G §196, §594: which modules exist, and the manifest of each, are the catalog half's; a branch with no first
|
|
// view yet is an error naming it, never no module, and an entry's manifest is the one it carries whole.
|
|
func TestCatalogHalfIsTheWatchedBranchesNewestRevision(t *testing.T) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
answered := false
|
|
var mu sync.Mutex
|
|
call := func(key string, _ any) (json.RawMessage, error) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
switch key {
|
|
case meshcatalogclient.RegistrationsVerb:
|
|
return json.Marshal(catalog.RegistrationsAnswer{Registrations: []catalog.Registration{{Module: "m", Version: 1, Branches: []string{"main"}}}})
|
|
case meshcatalogclient.SourceVerb:
|
|
return json.Marshal(delivery.SourceAnswer{})
|
|
case meshcatalogclient.RevisionVerb:
|
|
if !answered {
|
|
return nil, fmt.Errorf("the holder is away")
|
|
}
|
|
return json.Marshal(catalog.RevisionAnswer{Revision: &catalog.CatalogRevision{Revision: 1, Kind: meshcatalogclient.KindTrunk},
|
|
Entries: []catalog.CatalogEntry{{Module: "pg", Manifest: map[string]any{"module": "pg"}}}})
|
|
}
|
|
return nil, fmt.Errorf("asked %s", key)
|
|
}
|
|
w := &wiringOf{}
|
|
b, err := meshcatalogclient.NewBranches(w, call)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
h := b
|
|
if _, _, err := h.Entry("pg"); err == nil || !strings.Contains(err.Error(), "no watched branch") {
|
|
t.Fatalf("before the registrations: %v, want an error naming the missing branch", err)
|
|
}
|
|
go func() { _ = w.fs[0].Start(ctx) }() // the registrations
|
|
for len(b.Followed()) == 0 {
|
|
select {
|
|
case <-ctx.Done():
|
|
t.Fatal("the registrations' branch is never followed")
|
|
case <-time.After(10 * time.Millisecond):
|
|
}
|
|
}
|
|
if _, _, err := h.Entry("pg"); err == nil || !strings.Contains(err.Error(), "no first view of main") {
|
|
t.Fatalf("with no first view: %v, want an error naming the branch, never no module", err)
|
|
}
|
|
mu.Lock()
|
|
answered = true
|
|
mu.Unlock()
|
|
c, _ := b.Catalog("main")
|
|
if err := c.Start(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, ok, err := h.Entry("pg")
|
|
if err != nil || !ok || got.Manifest["module"] != "pg" || h.Ready() != nil {
|
|
t.Fatalf("with the first view: %v, %v, %v", got, ok, err)
|
|
}
|
|
if _, ok, err := h.Entry("absent"); ok || err != nil {
|
|
t.Fatalf("a module the half does not list: %v, %v", ok, err)
|
|
}
|
|
}
|