❯ go-clikit
v0.10.0 pkg.go.dev ↗

packages › progress & output › progress/progresstest

progresstest

import "github.com/GSI-HPC/go-clikit/progress/progresstest"

Capture the events that a command reports, draw them as a tree that does not depend on the order of the work, and check every promise.

since v0.1.0 imports: progress, termtextrequires: github.com/GSI-HPC/go-nodeset decisions 15
The place of progress/progresstest in go-clikit: the packages it imports, and the packages that import it.termtextprogressdisplaycliprogressprogresstestmcpprogresseventlogfanoutfanouttestclioutdoctorfsutilcobratreecobratreetestlocalwebsessionsselocalwebtestlaunchassetspagehtmx

progresstest captures the events of a test, draws them as a tree that reads the same however the concurrent work was scheduled, and checks that they keep the promises of progress to every sink.

_ = func(t *testing.T) {
	ctx, w := progresstest.Watch(t.Context(), t)
	_ = reset(ctx, []string{"exe1", "exe2", "exe3"})
	want := `step reset the machines total=3 [fold]: failed (target): exe3: no answer
  target exe3: failed (target): {}: no answer
  target exe[1-2]: ok
`
	if got := w.Finish(); got != want {
		t.Errorf("the work reported\n%s\nwant\n%s", got, want)
	}
}
ExampleWatch in progress/progresstest/example_test.go. CI compiles it.

The main names#

NameWhat it does
progresstest.Watch, progresstest.Watchera context with a Bus of its own; Finish checks and returns the tree
progresstest.Capturea sink that keeps the events; Tree draws them
progresstest.Checkthe rules, on events that you have
progresstest.Screena terminal in memory, for a test of what a display draws

What Check holds an emitter to#

Three rules shape how parallel work is reported. A pool written by hand breaks them most often:

  1. Every target of a folded step or a batch is announced queued before the first of them runs. A pool that starts each target in its own goroutine, as errgroup.Go does, breaks this.
  2. When a folded step or a batch ends, the targets that ended under it are its Total. A count never passes its Total, and a Total never shrinks.
  3. No more targets run at once below a span than its Limit.

The work of a span has rules too: two advances of a span come at least 100 ms apart, an amount is never negative, and the unit of a span never changes.

NOTE

The rules are an interface (decision 15). A new or stricter rule is a breaking change.

screen := &progresstest.Screen{Styles: true}
fmt.Fprint(screen, "\x1b[1;31m✗\x1b[0m exe0007\x1b[38;5;244m · \x1b[0mtransport\n")
fmt.Print(screen.String())
fmt.Print(screen.Styled())
✗ exe0007 · transport
«1;31»✗«» exe0007«38;5;244» · «»transport
ExampleScreen_Styled in progress/progresstest/example_test.go. CI runs it and checks its output.