mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
Inbound sync was invisible to the machine it landed on — a local index, cache or notifier had to poll. A `post_sync` command in the folder's own .bdrive/config.json now runs once per cycle that applied peer changes, with the batch as JSON on stdin. The batch rides out on a new Result.Inbound rather than the inbound spool: DrainInbound is destructive and `bdrive sync --hook` is its only consumer, so a second drainer would silently empty the agent's "teammates changed X" context. Both are kept, and both comments now say why. Cycle becomes a thin wrapper over cycleLocked so the hook is spawned after the volume flock drops — a property of the code shape, not a rule each of the seven call sites has to remember. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
58 lines
1.8 KiB
Go
58 lines
1.8 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// TestPostSyncRoundTrip: the hook command survives save/load, and stays out of
|
|
// the file entirely when unset.
|
|
func TestPostSyncRoundTrip(t *testing.T) {
|
|
folder := t.TempDir()
|
|
if _, err := SaveProject(folder, Project{ID: "m-1234abcd", Volume: "wiki", PostSync: "qmd update && qmd embed"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, ok, err := LoadProject(folder)
|
|
if err != nil || !ok {
|
|
t.Fatalf("LoadProject: %v (ok=%v)", err, ok)
|
|
}
|
|
if got.PostSync != "qmd update && qmd embed" {
|
|
t.Fatalf("post_sync = %q, want the saved command", got.PostSync)
|
|
}
|
|
|
|
if _, err := SaveProject(folder, Project{ID: "m-1234abcd", Volume: "wiki"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
raw, err := os.ReadFile(filepath.Join(folder, ProjectDir, "config.json"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if strings.Contains(string(raw), "post_sync") {
|
|
t.Fatalf("unset post_sync should be omitted, got %s", raw)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeInclude(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
in []string
|
|
want []string
|
|
}{
|
|
{in: nil, want: nil},
|
|
{in: []string{"wiki/"}, want: []string{"/wiki/"}}, // legacy config, anchored on read
|
|
{in: []string{"wiki"}, want: []string{"/wiki"}},
|
|
{in: []string{"/wiki/"}, want: []string{"/wiki/"}}, // already anchored
|
|
{in: []string{"a/b/"}, want: []string{"a/b/"}}, // compile() anchors these already
|
|
{in: []string{"*.md"}, want: []string{"*.md"}}, // deliberate pattern, left alone
|
|
{in: []string{"!keep"}, want: []string{"!keep"}},
|
|
{in: []string{"wiki/", "*.md"}, want: []string{"/wiki/", "*.md"}},
|
|
} {
|
|
in := append([]string(nil), tc.in...)
|
|
if got := normalizeInclude(tc.in); !reflect.DeepEqual(got, tc.want) {
|
|
t.Errorf("normalizeInclude(%q) = %q, want %q", in, got, tc.want)
|
|
}
|
|
}
|
|
}
|