Skip to content
quarry Artifact [5c0332ffc2]
Login

Artifact [5c0332ffc2]

Artifact 5c0332ffc237397f6604de7ebc099adcb3577bae686cde287d612026dbca91c0:


package xfer

import (
	"net/http"
	"net/http/httptest"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"testing"
)

// THE PUSH LISTENER HEARS A PUSH THAT LANDED, AND NOTHING ELSE.
//
// A tracking store that takes a push has diverged from its upstream,
// and the only place quarry knows a push was ADMITTED — not refused by
// the posture gate, not refused by the store — is the fronter, after
// the child's reply came back clean (5d40f151). A clone and a pull are
// not pushes; a refused push is not a push that landed.
func TestThePushListenerHearsOnlyAPushThatLanded(t *testing.T) {
	if _, err := exec.LookPath("zit"); err != nil {
		t.Skip("zit not on PATH")
	}
	origin := t.TempDir()
	zrun(t, origin, "init")
	if err := os.WriteFile(filepath.Join(origin, "README.md"), []byte("# pushed\n"), 0o644); err != nil {
		t.Fatal(err)
	}
	zrun(t, origin, "add", "README.md")
	zrun(t, origin, "commit", "-m", "first")

	var mu sync.Mutex
	var heard []string
	f := New()
	defer f.Close()
	f.Register("alpha", origin)
	f.SetPushed(func(repo string) {
		mu.Lock()
		defer mu.Unlock()
		heard = append(heard, repo)
	})
	mux := http.NewServeMux()
	mux.Handle("POST /r/{repo}", f)
	srv := httptest.NewServer(mux)
	defer srv.Close()

	work := t.TempDir()
	clone := filepath.Join(work, "clone")
	zrun(t, work, "clone", srv.URL+"/r/alpha", clone)
	zrun(t, clone, "pull")
	mu.Lock()
	n := len(heard)
	mu.Unlock()
	if n != 0 {
		t.Fatalf("FAIL: a clone and a pull were heard as pushes: %v", heard)
	}

	if err := os.WriteFile(filepath.Join(clone, "NOTES.md"), []byte("more\n"), 0o644); err != nil {
		t.Fatal(err)
	}
	zrun(t, clone, "add", "NOTES.md")
	zrun(t, clone, "commit", "-m", "second")
	zrun(t, clone, "push")
	mu.Lock()
	got := append([]string(nil), heard...)
	mu.Unlock()
	// A push is several rounds and each admitted round carrying a push
	// is heard: at least one, all on alpha. The listener counts
	// rounds, and its consumer treats them as "pushed at least once".
	if len(got) == 0 {
		t.Fatalf("FAIL: a push that landed was not heard")
	}
	for _, r := range got {
		if r != "alpha" {
			t.Fatalf("FAIL: heard %v, want only alpha", got)
		}
	}
	before := len(got)

	// A push the posture gate refuses is not heard.
	f.SetWriteGate(func(string) (bool, string) { return false, "https://up.example/r/alpha" })
	if err := os.WriteFile(filepath.Join(clone, "NOTES.md"), []byte("more still\n"), 0o644); err != nil {
		t.Fatal(err)
	}
	zrun(t, clone, "commit", "-m", "third")
	_ = zrunErr(clone, "push")
	mu.Lock()
	n = len(heard)
	mu.Unlock()
	if n != before {
		t.Fatalf("FAIL: a refused push was heard: %v", heard)
	}
	t.Log("ok: one push landed, one push heard")
}

// zrunErr runs zit and returns its error instead of failing the test,
// for the push that is meant to be refused.
func zrunErr(dir string, args ...string) error {
	cmd := exec.Command("zit", args...)
	cmd.Dir = dir
	return cmd.Run()
}