From 6992f958fc5eb8309f204da953664181256e96ed Mon Sep 17 00:00:00 2001 From: "M. J. Fromberger" Date: Wed, 17 Sep 2025 08:39:29 -0700 Subject: [PATCH] util/eventbus: add an EqualTo helper for testing (#17178) For a common case of events being simple struct types with some exported fields, add a helper to check (reflectively) for equal values using cmp.Diff so that a failed comparison gives a useful diff in the test output. More complex uses will still want to provide their own comparisons; this (intentionally) does not export diff options or other hooks from the cmp package. Updates #15160 Change-Id: I86bee1771cad7debd9e3491aa6713afe6fd577a6 Signed-off-by: M. J. Fromberger --- util/eventbus/eventbustest/eventbustest.go | 14 ++++++++ .../eventbustest/eventbustest_test.go | 35 ++++++++++++++----- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/util/eventbus/eventbustest/eventbustest.go b/util/eventbus/eventbustest/eventbustest.go index d5cfe5395..c32e71140 100644 --- a/util/eventbus/eventbustest/eventbustest.go +++ b/util/eventbus/eventbustest/eventbustest.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/google/go-cmp/cmp" "tailscale.com/util/eventbus" ) @@ -249,3 +250,16 @@ func Inject[T any](inj *Injector, event T) { } pub.(*eventbus.Publisher[T]).Publish(event) } + +// EqualTo returns an event-matching function for use with [Expect] and +// [ExpectExactly] that matches on an event of the given type that is equal to +// want by comparison with [cmp.Diff]. The expectation fails with an error +// message including the diff, if present. +func EqualTo[T any](want T) func(T) error { + return func(got T) error { + if diff := cmp.Diff(got, want); diff != "" { + return fmt.Errorf("wrong result (-got, +want):\n%s", diff) + } + return nil + } +} diff --git a/util/eventbus/eventbustest/eventbustest_test.go b/util/eventbus/eventbustest/eventbustest_test.go index 351553cc8..f8b37eefe 100644 --- a/util/eventbus/eventbustest/eventbustest_test.go +++ b/util/eventbus/eventbustest/eventbustest_test.go @@ -5,6 +5,7 @@ package eventbustest_test import ( "fmt" + "strings" "testing" "time" @@ -29,19 +30,17 @@ func TestExpectFilter(t *testing.T) { name string events []int expectFunc any - wantErr bool + wantErr string // if non-empty, an error is expected containing this text }{ { name: "single event", events: []int{42}, expectFunc: eventbustest.Type[EventFoo](), - wantErr: false, }, { name: "multiple events, single expectation", events: []int{42, 1, 2, 3, 4, 5}, expectFunc: eventbustest.Type[EventFoo](), - wantErr: false, }, { name: "filter on event with function", @@ -52,7 +51,6 @@ func TestExpectFilter(t *testing.T) { } return false, nil }, - wantErr: false, }, { name: "filter-with-nil-error", @@ -73,7 +71,7 @@ func TestExpectFilter(t *testing.T) { } return nil }, - wantErr: true, + wantErr: "value > 10", }, { name: "first event has to be func", @@ -84,7 +82,18 @@ func TestExpectFilter(t *testing.T) { } return false, nil }, - wantErr: true, + wantErr: "expected 42, got 24", + }, + { + name: "equal-values", + events: []int{23}, + expectFunc: eventbustest.EqualTo(EventFoo{Value: 23}), + }, + { + name: "unequal-values", + events: []int{37}, + expectFunc: eventbustest.EqualTo(EventFoo{Value: 23}), + wantErr: "wrong result (-got, +want)", }, { name: "no events", @@ -92,7 +101,7 @@ func TestExpectFilter(t *testing.T) { expectFunc: func(event EventFoo) (bool, error) { return true, nil }, - wantErr: true, + wantErr: "timed out waiting", }, } @@ -113,8 +122,16 @@ func TestExpectFilter(t *testing.T) { updater.Publish(EventFoo{i}) } - if err := eventbustest.Expect(tw, tt.expectFunc); (err != nil) != tt.wantErr { - t.Errorf("ExpectFilter[EventFoo]: error = %v, wantErr %v", err, tt.wantErr) + if err := eventbustest.Expect(tw, tt.expectFunc); err != nil { + if tt.wantErr == "" { + t.Errorf("Expect[EventFoo]: unexpected error: %v", err) + } else if !strings.Contains(err.Error(), tt.wantErr) { + t.Errorf("Expect[EventFoo]: err = %v, want %q", err, tt.wantErr) + } else { + t.Logf("Got expected error: %v (OK)", err) + } + } else if tt.wantErr != "" { + t.Errorf("Expect[EventFoo]: unexpectedly succeeded, want error %q", tt.wantErr) } }) }