Skip to content
quarry Artifact [9827b2cd28]
Login

Artifact [9827b2cd28]

Artifact 9827b2cd28e1cb15fb347e623d8f8bd99fdc0c074473ba5867877c84f65aab69:


package events

import (
	"testing"

	"craftdesign.group/quarry/internal/evt"
)

// ForgetRepo takes a deleted repository's attention events, its event
// log and its traffic tallies, so a repository created later under the
// name inherits none of them — and a neighbour whose name merely starts
// with the deleted one's keeps all of its own (quarry#294).
func TestForgetRepoTakesOnlyThatRepository(t *testing.T) {
	s := testServer(t)
	const gone, dotted, kept = "gone", "gone.x", "kept"
	for _, repo := range []string{gone, dotted, kept} {
		for _, who := range []string{"ann", "bob"} {
			if _, err := s.Attend(who, AttentionEvent{Kind: "mention", Repo: repo, Link: "/r/" + repo}); err != nil {
				t.Fatal(err)
			}
		}
		if err := s.Raise(evt.TicketClosed, repo, map[string]any{"repo": repo}); err != nil {
			t.Fatal(err)
		}
		for _, name := range []string{"clone", "clone.auth.ann", "clone.client.zit.v1", "fetch.anon"} {
			if err := s.Count(repo, name, 1); err != nil {
				t.Fatal(err)
			}
		}
	}
	if err := s.ForgetRepo(gone); err != nil {
		t.Fatal(err)
	}

	for _, who := range []string{"ann", "bob"} {
		evs, err := s.RecentAttention(who, 50)
		if err != nil {
			t.Fatal(err)
		}
		held := map[string]int{}
		for _, e := range evs {
			held[e.Repo]++
		}
		if held[gone] != 0 {
			t.Errorf("%s still holds %d attention events for the deleted repository", who, held[gone])
		}
		if held[dotted] != 1 || held[kept] != 1 {
			t.Errorf("%s lost a neighbour's attention events: %v", who, held)
		}
	}

	logged, err := s.Recent(gone, 50)
	if err != nil {
		t.Fatal(err)
	}
	for _, l := range logged {
		if l.Repo == gone {
			t.Errorf("the deleted repository's event log survived: %+v", l)
		}
	}
	for _, repo := range []string{dotted, kept} {
		if l, err := s.Recent(repo, 50); err != nil || len(l) == 0 {
			t.Errorf("%s's event log went with %s's: %d, %v", repo, gone, len(l), err)
		}
	}

	for _, fam := range []string{"clone", "fetch"} {
		if tot, err := s.Totals(gone, fam); err != nil || len(tot) != 0 {
			t.Errorf("%s's %s tallies survived: %v, %v", gone, fam, tot, err)
		}
	}
	if n, _ := s.Total(gone, "clone"); n != 0 {
		t.Errorf("%s's clone total survived: %d", gone, n)
	}
	for _, repo := range []string{dotted, kept} {
		if n, _ := s.Total(repo, "clone"); n != 1 {
			t.Errorf("%s's clone total = %d, want 1", repo, n)
		}
		if tot, _ := s.Totals(repo, "clone"); tot["auth.ann"] != 1 {
			t.Errorf("%s's clone tallies went too: %v", repo, tot)
		}
	}
}

// A store re-added under the same project code finds no publisher
// cursor, publish record or fold mark of the deleted one: a surviving
// cursor over an emptied index would skip the census (quarry#294).
func TestForgetStoreTakesItsCursorKeys(t *testing.T) {
	s := testServer(t)
	kv, err := s.Cursors()
	if err != nil {
		t.Fatal(err)
	}
	const code, other = "aaaa1111", "aaaa11112"
	keys := []string{code, "pub." + code, "seen.indexer-" + code, "seen.indexer-" + code + "-0123456789ab", other, "pub." + other}
	for _, k := range keys {
		if _, err := kv.Put(k, []byte("{}")); err != nil {
			t.Fatal(err)
		}
	}
	if err := s.ForgetStore(code); err != nil {
		t.Fatal(err)
	}
	for _, k := range keys[:4] {
		if _, err := kv.Get(k); err == nil {
			t.Errorf("%s survived", k)
		}
	}
	for _, k := range keys[4:] {
		if _, err := kv.Get(k); err != nil {
			t.Errorf("%s went with %s: %v", k, code, err)
		}
	}
}

// A scan that gets short batches off a large stream still finds every
// message: it ends when the consumer has nothing pending, not on the
// first batch under the size asked for.
func TestForgetRepoSurvivesShortBatches(t *testing.T) {
	s := testServer(t)
	old := forgetBatch
	forgetBatch = 3
	t.Cleanup(func() { forgetBatch = old })
	for i := 0; i < 20; i++ {
		if _, err := s.Attend("ann", AttentionEvent{Kind: "mention", Repo: "gone", Link: "/r/gone"}); err != nil {
			t.Fatal(err)
		}
	}
	if err := s.ForgetRepo("gone"); err != nil {
		t.Fatal(err)
	}
	evs, err := s.RecentAttention("ann", 50)
	if err != nil {
		t.Fatal(err)
	}
	if len(evs) != 0 {
		t.Errorf("%d events survived", len(evs))
	}
}