Skip to content

Commit

Permalink
🫠 check: add run summary
Browse files Browse the repository at this point in the history
  • Loading branch information
rjeczalik committed Jul 4, 2024
1 parent 9046fcc commit 5ce649f
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 44 deletions.
7 changes: 4 additions & 3 deletions hkt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,13 @@ func newRunCommand(ctx context.Context, app *command.App) *cobra.Command {
if cmd.Flags().Changed("debug") {
ctx = trace.WithJob(ctx, trace.LogJob())
ctx = trace.WithPattern(ctx, trace.LogPattern())
ctx = trace.WithSchedule(ctx, trace.LogSchedule())
}

s, err := app.Engine.Run(ctx, files[0])

app.Render(s.Events)

if s != nil && len(s.Events) != 0 {
app.Render(s.Results())
}
return err
},
Version: version,
Expand Down
112 changes: 93 additions & 19 deletions pkg/check/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,45 @@ func (s *S) Fail() {
s.mu.Unlock()
}

func (s *S) Results() []Result {
var res []Result
for i, e := range s.Events {
f := makeFailures(e.Match, false)
if len(f) > 0 {
res = append(res, Result{
Type: "match",
Index: i,
Step: e.Desc,
Failures: f,
})
continue
}

f = makeFailures(e.Fail, true)
if len(f) > 0 {
res = append(res, Result{
Type: "fail",
Index: i,
Step: e.Desc,
Failures: f,
})
continue
}

f = makeFailures(e.Pass, false)
if len(f) > 0 {
res = append(res, Result{
Type: "pass",
Index: i,
Step: e.Desc,
Failures: f,
})
continue
}
}
return res
}

func (s *S) Trace() trace.PatternTrace {
return trace.PatternTrace{
ParseKey: func(ctx context.Context, q *gojq.Query, err error) {
Expand All @@ -55,52 +94,87 @@ func (s *S) Trace() trace.PatternTrace {
}

s.Events[n].Desc = desc
s.Events[n].MarkPattern(group, pattern, false)
s.Events[n].MarkPattern(group, pattern, Value{
OK: false,
})
},
EqualMatch: func(ctx context.Context, a, b any, eq bool) {
if !eq {
return
}

EqualMatch: func(ctx context.Context, want, got any, ok bool) {
n, _ := strconv.Atoi(trace.Get(ctx, "step-index"))
group := trace.Get(ctx, "pattern-group")
pattern := trace.Get(ctx, "pattern")

s.mu.Lock()
defer s.mu.Unlock()

s.Events[n].MarkPattern(group, pattern, eq)
s.Events[n].MarkPattern(group, pattern, Value{
Want: want,
Got: got,
OK: ok,
})
},
}
}

func (e *Event) MarkPattern(group, pattern string, ok bool) {
func (e *Event) MarkPattern(group, pattern string, v Value) {
switch group {
case "match":
if e.Match == nil {
e.Match = make(map[string]bool)
e.Match = make(map[string]Value)
}
e.Match[pattern] = ok
e.Match[pattern] = v
case "pass":
if e.Pass == nil {
e.Pass = make(map[string]bool)
e.Pass = make(map[string]Value)
}
e.Pass[pattern] = ok
e.Pass[pattern] = v
case "fail":
if e.Fail == nil {
e.Fail = make(map[string]bool)
e.Fail = make(map[string]Value)
}
e.Fail[pattern] = ok
e.Fail[pattern] = v
default:
panic(fmt.Errorf("unknown group: %q (pattern=%q, ok=%v)", group, pattern, ok))
panic(fmt.Errorf("unknown group: %q (pattern=%q, ok=%v)", group, pattern, v))
}
}

type Value struct {
Got any `json:"got,omitempty"`
Want any `json:"want,omitempty"`
OK bool `json:"ok"`
}

type Event struct {
Desc string `json:"desc,omitempty"`
Match map[string]bool `json:"match"`
Pass map[string]bool `json:"pass,omitempty"`
Fail map[string]bool `json:"fail,omitempty"`
Desc string `json:"desc,omitempty"`
Match map[string]Value `json:"match"`
Pass map[string]Value `json:"pass,omitempty"`
Fail map[string]Value `json:"fail,omitempty"`
}

type Events []*Event

type Result struct {
Type string `json:"type"`
Step string `json:"step"`
Index int `json:"index"`
Failures []Failure `json:"failures"`
}

type Failure struct {
Key string `json:"key"`
Got any `json:"got"`
Expected any `json:"expected"`
}

func makeFailures(m map[string]Value, ok bool) []Failure {
var failures []Failure
for key, v := range m {
if v.OK == ok {
failures = append(failures, Failure{
Key: key,
Got: v.Got,
Expected: v.Want,
})
}
}
return failures
}
2 changes: 1 addition & 1 deletion pkg/hookt/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (e *Engine) Run(ctx context.Context, file string) (*check.S, error) {
return errors.New("step %q does not implement proto.Runner", step.ID)
}

defer r.Stop()
defer r.Stop(ctx)

if err := r.Run(ctx, &s); err != nil {
slog.Error("step failure",
Expand Down
47 changes: 34 additions & 13 deletions pkg/plugin/builtin/event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ wire:
return errors.New("source %q not found in job plugins", source)
}

go p.schedule()
go p.schedule(ctx)

slog.Debug("event: init",
"config", p.Config,
Expand All @@ -91,14 +91,20 @@ wire:
return nil
}

func (p *Plugin) schedule() {
func (p *Plugin) schedule(ctx context.Context) {
tr := trace.ContextSchedule(ctx)

for {
select {
case i := <-p.stop:
s := &p.steps[i]
close(s.done)
s.done = nil
tr.Stop(ctx, i)
case msg := <-p.mux:
ctxt := ctx
if idx, ok := msg.(Indexer); ok {
ctxt = trace.With(ctxt, "event-seq", strconv.Itoa(idx.Index()))
}
var steps []step
for _, step := range p.steps {
if step.done == nil {
Expand All @@ -109,28 +115,37 @@ func (p *Plugin) schedule() {
switch p.Config.Mode {
case "sync":
wg := Wait(msg)
go func() {
for _, step := range steps {
go func(ctx context.Context) {
for i, step := range steps {
tr.BeforeMux(ctx, msg, i)
select {
case <-step.done:
tr.Done(ctx, msg, i)
continue
case step.c <- wg:
if wg.Wait() {
tr.Mux(ctx, msg, i)

ok := wg.Wait()
tr.Wait(ctx, msg, i, ok)
if ok {
return
}
}
}
}()
}(ctxt)
case "", "async":
go func() {
for _, step := range steps {
go func(ctx context.Context) {
for i, step := range steps {
tr.BeforeMux(ctx, msg, i)
select {
case <-step.done:
tr.Done(ctx, msg, i)
continue
case step.c <- msg:
tr.Mux(ctx, msg, i)
}
}
}()
}(ctxt)
}
}
}
Expand Down Expand Up @@ -247,9 +262,13 @@ func (s *Step) Run(ctx context.Context, c *check.S) error {
return nil
}

func (s *Step) Stop() {
func (s *Step) Stop(ctx context.Context) {
tr := trace.ContextSchedule(ctx)

tr.BeforeStop(ctx, s.i)
s.p.stop <- s.i
s.drain()
tr.Drain(ctx, s.i)
}

func (s *Step) step() step {
Expand All @@ -259,8 +278,10 @@ func (s *Step) step() step {
func (s *Step) drain() {
for {
select {
case _ = <-s.step().c:
// drop the event
case msg := <-s.step().c:
if wg, ok := msg.(WaitMessage); ok {
wg.Done(false)
}
case <-s.step().done:
return
}
Expand Down
27 changes: 21 additions & 6 deletions pkg/plugin/builtin/inline/inline.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import (
"io"
"log/slog"
"os"
"strconv"
"strings"

"hookt.dev/cmd/pkg/plugin/builtin/inline/wire"
"hookt.dev/cmd/pkg/proto"
protowire "hookt.dev/cmd/pkg/proto/wire"
"hookt.dev/cmd/pkg/trace"

"github.com/lmittmann/tint"
)
Expand Down Expand Up @@ -46,7 +48,7 @@ func (p *Plugin) Plugin(_ context.Context, q *proto.P) any {
return p.WithProto(q)
}

func (p *Plugin) Init(context.Context, *proto.Job) error {
func (p *Plugin) Init(ctx context.Context, _ *proto.Job) error {
slog.Debug("inline: init",
"config", p.Config,
)
Expand All @@ -65,15 +67,18 @@ func (p *Plugin) Init(context.Context, *proto.Job) error {
return err
}

go p.publish(f)
go p.publish(ctx, f)

return nil
}

func (p *Plugin) publish(f *os.File) {
func (p *Plugin) publish(ctx context.Context, f *os.File) {
defer f.Close()

dec := json.NewDecoder(f)
var (
dec = json.NewDecoder(f)
tr = trace.ContextSchedule(ctx)
)

for index := 0; ; index++ {
var raw json.RawMessage
Expand All @@ -91,13 +96,19 @@ func (p *Plugin) publish(f *os.File) {
return
}

ctx := trace.With(ctx, "event-seq", strconv.Itoa(index))

switch raw[0] {
case '{':
slog.Debug("inline: publish",
"bytes", len(raw),
)

p.c <- &protowire.Message{P: raw, I: index}
msg := &protowire.Message{P: raw, I: index}

tr.BeforePublish(ctx, msg)
p.c <- msg
tr.Publish(ctx, msg)
case '[':
var msgs []json.RawMessage

Expand All @@ -114,7 +125,11 @@ func (p *Plugin) publish(f *os.File) {
"bytes", len(msgs[i]),
)

p.c <- &protowire.Message{P: msgs[i], I: index}
msg := &protowire.Message{P: msgs[i], I: index}

tr.BeforePublish(ctx, msg)
p.c <- msg
tr.Publish(ctx, msg)
}
default:
err = errors.New("unexpected JSON input")
Expand Down
6 changes: 5 additions & 1 deletion pkg/proto/pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,11 @@ func (p *P) Patterns(ctx context.Context, obj wire.Object) (Patterns, error) {

switch want := want.(type) {
case bool:
q.Match = func(_ context.Context, got any) (bool, error) { return want || got == nil, nil }
q.Match = func(_ context.Context, got any) (bool, error) {
ok := want && len(raw) != 0
tr.EqualMatch(ctx, want, got, ok)
return ok, nil
}
case string:
q.Match = p.t.Match(ctx, want)
default:
Expand Down
2 changes: 1 addition & 1 deletion pkg/proto/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ type Initializer interface {

type Runner interface {
Run(context.Context, *check.S) error
Stop()
Stop(ctx context.Context)
}
Loading

0 comments on commit 5ce649f

Please sign in to comment.