Skip to content
quarry Artifact [216075ecbd]
Login

Artifact [216075ecbd]

Artifact 216075ecbd486aee906e6ea0fd57b24f50a9b9cad3538be28c2c58a9323e41a7:


package api

import (
	"context"
	"testing"

	"craftdesign.group/quarry/internal/ops"
	"craftdesign.group/quarry/internal/work"
	"craftdesign.group/quarry/internal/zitcli"
)

// The ops panel can only show the lanes it is handed, and the two this
// package can see are not the ones that shed. On zeitforge the ingest
// lane refused tcl 7.8 times an hour for a week while this panel — the
// panel for exactly that question — listed the store and archive lanes,
// both idle.
func TestTheOpsPanelListsEveryLaneTheProcessOwns(t *testing.T) {
	ingest := work.NewLane("ingest", 3, 22)
	d := Deps{Version: "v", Repos: NewRepos(map[string]*Repo{}),
		Lanes: func() []zitcli.Lane {
			st := ingest.Stats()
			return []zitcli.Lane{{Name: st.Name, Bound: st.Limit,
				Running: int(st.InFlight), Admitted: int(st.Admitted),
				Refused: int(st.Shed), Waiting: st.Waiting, Queue: st.Queue}}
		}}
	r := ops.NewRegistry()
	if err := RegisterAll(r, d); err != nil {
		t.Fatal(err)
	}
	got, err := r.Invoke(ops.WithUser(context.Background(), "dan"), "ops.status", opsStatusIn{})
	if err != nil {
		t.Fatal(err)
	}
	names := map[string]bool{}
	var ingestLane zitcli.Lane
	for _, l := range got.(opsStatusOut).Lanes {
		names[l.Name] = true
		if l.Name == "ingest" {
			ingestLane = l
		}
	}
	for _, want := range []string{"store subprocesses", "archive builds", "ingest"} {
		if !names[want] {
			t.Errorf("FAIL: the panel does not list the %q lane: %v", want, names)
		}
	}
	// The depth is what distinguishes "the queue is full" from "slots
	// are held too long" — running and refused alone cannot.
	if ingestLane.Queue != 22 || ingestLane.Bound != 3 {
		t.Errorf("FAIL: the ingest lane reports bound %d queue %d, want 3 and 22",
			ingestLane.Bound, ingestLane.Queue)
	}
}

// A forge with no extra lanes still reports the four it has (the store
// gate and the three archive lanes), rather than
// failing because nothing was injected.
func TestAForgeWithNoExtraLanesStillReportsItsOwn(t *testing.T) {
	r := ops.NewRegistry()
	if err := RegisterAll(r, Deps{Version: "v", Repos: NewRepos(map[string]*Repo{})}); err != nil {
		t.Fatal(err)
	}
	got, err := r.Invoke(ops.WithUser(context.Background(), "dan"), "ops.status", opsStatusIn{})
	if err != nil {
		t.Fatal(err)
	}
	if n := len(got.(opsStatusOut).Lanes); n != 4 {
		t.Errorf("FAIL: %d lanes with none injected, want the four internal ones", n)
	}
}

// A lane that actually shed reports it, so the number the fault names
// and the number the panel shows are the same number.
func TestASaturatedLaneReportsWhatItRefused(t *testing.T) {
	lane := work.NewLane("ingest", 1, 0)
	release := make(chan struct{})
	admitted := make(chan struct{})
	go lane.Do(context.Background(), func() error {
		close(admitted)
		<-release
		return nil
	})
	<-admitted
	// The one slot is held, the queue is zero, so this is refused.
	if err := lane.Do(context.Background(), func() error { return nil }); err == nil {
		t.Fatal("FAIL: a full lane with no queue admitted a second caller")
	}
	close(release)
	if st := lane.Stats(); st.Shed != 1 {
		t.Errorf("FAIL: Stats reports %d shed, want 1", st.Shed)
	}
}