Skip to content
quarry Artifact [eb15dd4847]
Login

Artifact [eb15dd4847]

Artifact eb15dd48478abf0f7b4293cbeb2ac8b76361ddbd98f8f17a0fdc177c80e6a7db:


package evt

import "testing"

// A subscription naming a noun selects every action on it, including ones
// added after the subscription was written. That is the entire argument for
// noun-and-action over Gitea's one-name-per-verb, so it is the thing to pin.
func TestANounSelectsEveryActionOnIt(t *testing.T) {
	if !TicketClosed.Matches("ticket") {
		t.Error(`"ticket" does not select ticket.closed`)
	}
	if !TicketOpened.Matches("ticket") {
		t.Error(`"ticket" does not select ticket.opened`)
	}
	if !TicketClosed.Matches("ticket.closed") {
		t.Error("an exact kind does not select itself")
	}
	// Precision is available where it is wanted.
	if TicketOpened.Matches("ticket.closed") {
		t.Error("ticket.closed selected ticket.opened")
	}
	// A noun does not reach across nouns, however similar the names.
	if LandingOpened.Matches("ticket") {
		t.Error("a noun selected another noun's event")
	}
	// A pattern naming a noun that does not exist selects nothing rather
	// than everything — the failure of a typo must be silence, not a
	// firehose.
	if TicketClosed.Matches("tickets") || TicketClosed.Matches("") {
		t.Error("a bad pattern matched")
	}
}

// The bus is a one-hour window, so what happens to a missed event depends on
// whether it can be re-derived from the store. Getting this classification
// wrong is how an operational fact — a failed mirror pull — silently does not
// happen, so each noun is asserted rather than the rule restated.
func TestDerivedEventsAreExactlyTheOnesTheStoreHolds(t *testing.T) {
	for _, k := range []Kind{CheckinCreated, BranchMoved, TagCreated,
		TicketClosed, WikiEdited, TechnoteCreated, ForumPosted, LandingAccepted} {
		if !k.Derived() {
			t.Errorf("%s is a reading of stored artifacts and should be derived", k)
		}
	}
	// None of these is in the DAG: missing one loses the fact, so each
	// must be recorded in OLTP as it is raised.
	for _, k := range []Kind{CICompleted, MirrorFailed, RepoCreated,
		AccountCaps, CloneCloned} {
		if k.Derived() {
			t.Errorf("%s is not in the store and must not be treated as re-derivable", k)
		}
	}
}

// An unknown name is refused where the subscription is written. A pipeline
// that never runs and a pipeline that runs and fails look nothing alike to
// the person waiting for it.
func TestUnknownKindsAreRefused(t *testing.T) {
	for _, bad := range []Kind{"ticket.exploded", "issue.opened", "checkin", ""} {
		if bad.Valid() {
			t.Errorf("%q was accepted into the vocabulary", bad)
		}
	}
	for _, k := range All {
		if !k.Valid() {
			t.Errorf("%s is in All but not Valid", k)
		}
		if k.Noun() == "" || k.Action() == "" {
			t.Errorf("%s is not noun.action", k)
		}
	}
}

// The vocabulary is a published interface: a name in someone else's pipeline
// definition. This pins the set so a rename is a deliberate act with a
// failing test attached, not a refactor that quietly breaks every store.
func TestTheVocabularyIsFixed(t *testing.T) {
	if got, want := len(All), 35; got != want {
		t.Errorf("the vocabulary changed size: %d, was %d — if deliberate, say so in RFC 0005", got, want)
	}
	want := []string{"checkin", "branch", "tag", "ticket", "wiki", "technote",
		"forum", "landing", "ci", "mirror", "repo", "account", "clone"}
	got := Nouns()
	if len(got) != len(want) {
		t.Fatalf("nouns = %v, want %v", got, want)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("nouns = %v, want %v", got, want)
		}
	}
}